提交 d65b9ba0 编写于 作者: C CyrusNajmabadi

Unify infrastructure for snippets between C# and VB.

上级 37986f57
......@@ -54,11 +54,6 @@ public IReadOnlyList<TextSpan> GetHighlightedSpans(CompletionItem completionItem
return match?.MatchedSpans;
}
/// <summary>
/// If true then a [TAB] after a question mark brings up completion.
/// </summary>
public virtual bool QuestionTabInvokesSnippetCompletion => false;
/// <summary>
/// Returns true if the completion item matches the filter text typed so far. Returns 'true'
/// iff the completion item matches and should be included in the filtered completion
......
......@@ -25,13 +25,10 @@ void ICommandHandler<TabKeyCommandArgs>.ExecuteCommand(TabKeyCommandArgs args, A
if (sessionOpt == null)
{
// The user may be trying to invoke snippets in VB
var helper = GetCompletionHelper();
// The user may be trying to invoke snippets through question-tab
var completionService = GetCompletionService();
if (helper != null &&
completionService != null &&
helper.QuestionTabInvokesSnippetCompletion &&
if (completionService != null &&
TryInvokeSnippetCompletion(args, completionService))
{
// We've taken care of the tab. Don't send it to the buffer.
......@@ -67,60 +64,91 @@ private bool TryInvokeSnippetCompletion(TabKeyCommandArgs args, CompletionServic
var text = subjectBuffer.AsTextContainer().CurrentText;
// Delete the ? and invoke completion
// If the user types "<line start><spaces><question><tab>"
// then the editor takes over and shows the normal *full* snippet picker UI.
// i.e. the picker with all the folders and snippet organization.
//
// However, if the user instead has something like
//
// "<line start><spaces><identifier><question><tab>"
//
// Then we take over and we show a completion list with all snippets in it
// in a flat list. This enables simple browsing and filtering of all items
// based on what the user typed so far.
//
// If we detect this pattern, then we delete the previous character (the
// question mark) and we don't send the tab through to the editor. In
// essence, the <quesiton><tab> acts as the trigger, and we act as if that
// text never makes it into the buffer.
Workspace workspace = null;
if (Workspace.TryGetWorkspace(subjectBuffer.AsTextContainer(), out workspace))
if (!Workspace.TryGetWorkspace(subjectBuffer.AsTextContainer(), out workspace))
{
var documentId = workspace.GetDocumentIdInCurrentContext(subjectBuffer.AsTextContainer());
if (documentId != null)
{
var document = workspace.CurrentSolution.GetDocument(documentId);
if (document != null)
{
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
if (caretPoint >= 2 && text[caretPoint - 1] == '?' && QuestionMarkIsPrecededByIdentifierAndWhitespace(text, caretPoint - 2, syntaxFacts))
{
var textChange = new TextChange(TextSpan.FromBounds(caretPoint - 1, caretPoint), string.Empty);
workspace.ApplyTextChanges(documentId, textChange, CancellationToken.None);
this.StartNewModelComputation(completionService, new CompletionTrigger(CompletionTriggerKind.Snippets), filterItems: false);
return true;
}
}
}
return false;
}
var documentId = workspace.GetDocumentIdInCurrentContext(subjectBuffer.AsTextContainer());
if (documentId == null)
{
return false;
}
var document = workspace.CurrentSolution.GetDocument(documentId);
if (document == null)
{
return false;
}
var rules = GetCompletionService().GetRules();
if (rules.SnippetsRule != SnippetsRule.IncludeAfterTypingIdentifierQuestionTab)
{
return false;
}
return false;
var syntaxFactsOpt = document.GetLanguageService<ISyntaxFactsService>();
if (syntaxFactsOpt == null ||
caretPoint < 2 ||
text[caretPoint - 1] != '?' ||
!QuestionMarkIsPrecededByIdentifierAndWhitespace(text, caretPoint - 1, syntaxFactsOpt))
{
return false;
}
// Because <question><tab> is actually a command to bring up snippets,
// we delete the last <question> that was typed.
var textChange = new TextChange(TextSpan.FromBounds(caretPoint - 1, caretPoint), string.Empty);
workspace.ApplyTextChanges(documentId, textChange, CancellationToken.None);
this.StartNewModelComputation(completionService, new CompletionTrigger(CompletionTriggerKind.Snippets), filterItems: false);
return true;
}
private bool QuestionMarkIsPrecededByIdentifierAndWhitespace(SourceText text, int p, ISyntaxFactsService syntaxFacts)
private bool QuestionMarkIsPrecededByIdentifierAndWhitespace(
SourceText text, int questionPosition, ISyntaxFactsService syntaxFacts)
{
int start = text.Lines.GetLineFromPosition(p).Start;
bool seenIdentifier = false;
var startOfLine = text.Lines.GetLineFromPosition(questionPosition).Start;
while (p >= start)
// First, skip all the whitespace.
var current = startOfLine;
while (current < questionPosition && char.IsWhiteSpace(text[current]))
{
if (!(syntaxFacts.IsIdentifierStartCharacter(text[p]) || syntaxFacts.IsIdentifierPartCharacter(text[p])))
{
break;
}
seenIdentifier = true;
p--;
current++;
}
while (p >= start)
if (current < questionPosition && syntaxFacts.IsIdentifierStartCharacter(text[current]))
{
if (!char.IsWhiteSpace(text[p]))
{
break;
}
current++;
}
else
{
return false;
}
p--;
while (current < questionPosition && syntaxFacts.IsIdentifierPartCharacter(text[current]))
{
current++;
}
return seenIdentifier && p <= start;
return current == questionPosition;
}
private void CommitOnTab(out bool committed)
......
......@@ -35,12 +35,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Completion
MyBase.New(isCaseSensitive:=False)
End Sub
Public Overrides ReadOnly Property QuestionTabInvokesSnippetCompletion As Boolean
Get
Return True
End Get
End Property
Public Overrides Function MatchesFilterText(item As CompletionItem, filterText As String, trigger As CompletionTrigger, filterReason As CompletionFilterReason, Optional recentItems As ImmutableArray(Of String) = Nothing) As Boolean
' If this Is a session started on backspace, we use a much looser prefix match check
' to see if an item matches
......
......@@ -12,6 +12,7 @@ internal static class CSharpCompletionOptions
[Obsolete("This option is superceded by CompletionOptions.EnterKeyBehavior")]
public static readonly Option<bool> AddNewLineOnEnterAfterFullyTypedWord = new Option<bool>(FeatureName, "Add New Line On Enter After Fully Typed Word", defaultValue: false);
[Obsolete("This option is superceded by CompletionOptions.SnippetsBehavior")]
public static readonly Option<bool> IncludeSnippets = new Option<bool>(FeatureName, "Include Code Snippets", defaultValue: true);
}
}
......@@ -5,16 +5,14 @@
using System.Composition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Options.Providers;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Completion
{
[ExportOptionProvider, Shared]
internal class CSharpCompletionOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = new List<IOption>
{
CSharpCompletionOptions.IncludeSnippets,
}.ToImmutableArray();
private readonly IEnumerable<IOption> _options = SpecializedCollections.EmptyEnumerable<IOption>();
public IEnumerable<IOption> GetOptions()
{
......
......@@ -78,17 +78,24 @@ public override CompletionRules GetRules()
{
var options = _workspace.Options;
var rule = options.GetOption(CompletionOptions.EnterKeyBehavior, LanguageNames.CSharp);
var enterRule = options.GetOption(CompletionOptions.EnterKeyBehavior, LanguageNames.CSharp);
var snippetRule = options.GetOption(CompletionOptions.SnippetsBehavior, LanguageNames.CSharp);
// Although EnterKeyBehavior is a per-language setting, the meaning of an unset setting (Default) differs between C# and VB
// In C# the default means Never to maintain previous behavior
if (rule == EnterKeyRule.Default)
if (enterRule == EnterKeyRule.Default)
{
rule = EnterKeyRule.Never;
enterRule = EnterKeyRule.Never;
}
if (snippetRule == SnippetsRule.Default)
{
snippetRule = SnippetsRule.AlwaysInclude;
}
// use interlocked + stored rules to reduce # of times this gets created when option is different than default
var newRules = _latestRules.WithDefaultEnterKeyRule(rule);
var newRules = _latestRules.WithDefaultEnterKeyRule(enterRule)
.WithSnippetsRule(snippetRule);
Interlocked.Exchange(ref _latestRules, newRules);
......
......@@ -24,10 +24,7 @@ internal sealed class SnippetCompletionProvider : CommonCompletionProvider
// If null, the document's language service will be used.
private readonly ISnippetInfoService _snippetInfoService;
internal override bool IsSnippetProvider
{
get { return true; }
}
internal override bool IsSnippetProvider => true;
public SnippetCompletionProvider(ISnippetInfoService snippetInfoService = null)
{
......@@ -36,11 +33,6 @@ public SnippetCompletionProvider(ISnippetInfoService snippetInfoService = null)
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options)
{
if (!options.GetOption(CSharpCompletionOptions.IncludeSnippets))
{
return false;
}
return CompletionUtilities.IsTriggerCharacter(text, characterPosition, options);
}
......@@ -62,11 +54,6 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
return;
}
if (!options.GetOption(CSharpCompletionOptions.IncludeSnippets))
{
return;
}
var snippetCompletionItems = await document.GetUnionItemsFromDocumentAndLinkedDocumentsAsync(
UnionCompletionItemComparer.Instance,
(d, c) => GetSnippetsForDocumentAsync(d, position, context.DefaultItemSpan, workspace, c),
......
......@@ -10,12 +10,13 @@ internal static class CompletionOptions
internal const string FeatureName = "Completion";
public static readonly PerLanguageOption<bool> HideAdvancedMembers = new PerLanguageOption<bool>(FeatureName, "HideAdvancedMembers", defaultValue: false);
public static readonly PerLanguageOption<bool> IncludeKeywords = new PerLanguageOption<bool>(FeatureName, "IncludeKeywords", defaultValue: true);
public static readonly PerLanguageOption<bool> TriggerOnTyping = new PerLanguageOption<bool>(FeatureName, "TriggerOnTyping", defaultValue: true);
public static readonly PerLanguageOption<bool> TriggerOnTypingLetters = new PerLanguageOption<bool>(FeatureName, "TriggerOnTypingLetters", defaultValue: true);
public static readonly PerLanguageOption<EnterKeyRule> EnterKeyBehavior =
new PerLanguageOption<EnterKeyRule>(FeatureName, nameof(EnterKeyBehavior), defaultValue: EnterKeyRule.Default);
public static readonly PerLanguageOption<SnippetsRule> SnippetsBehavior =
new PerLanguageOption<SnippetsRule>(FeatureName, nameof(SnippetsBehavior), defaultValue: SnippetsRule.Default);
// Dev15 options
public static readonly PerLanguageOption<bool> ShowCompletionItemFilters = new PerLanguageOption<bool>(FeatureName, nameof(ShowCompletionItemFilters), defaultValue: false);
......
......@@ -13,12 +13,12 @@ internal class CompletionOptionsProvider : IOptionProvider
{
private readonly IEnumerable<IOption> _options = ImmutableArray.Create<IOption>(
CompletionOptions.HideAdvancedMembers,
CompletionOptions.IncludeKeywords,
CompletionOptions.TriggerOnTyping,
CompletionOptions.TriggerOnTypingLetters,
CompletionOptions.ShowCompletionItemFilters,
CompletionOptions.HighlightMatchingPortionsOfCompletionListItems,
CompletionOptions.EnterKeyBehavior);
CompletionOptions.EnterKeyBehavior,
CompletionOptions.SnippetsBehavior);
public IEnumerable<IOption> GetOptions() => _options;
}
......
......@@ -33,16 +33,23 @@ public sealed class CompletionRules
/// </summary>
public EnterKeyRule DefaultEnterKeyRule { get; }
/// <summary>
/// The rule determing how snippets work.
/// </summary>
public SnippetsRule SnippetsRule { get; }
private CompletionRules(
bool dismissIfEmpty,
bool dismissIfLastCharacterDeleted,
ImmutableArray<char> defaultCommitCharacters,
EnterKeyRule defaultEnterKeyRule)
EnterKeyRule defaultEnterKeyRule,
SnippetsRule snippetsRule)
{
this.DismissIfEmpty = dismissIfEmpty;
this.DismissIfLastCharacterDeleted = dismissIfLastCharacterDeleted;
this.DefaultCommitCharacters = defaultCommitCharacters.IsDefault ? ImmutableArray<char>.Empty : defaultCommitCharacters;
this.DefaultEnterKeyRule = defaultEnterKeyRule;
this.SnippetsRule = snippetsRule;
}
/// <summary>
......@@ -52,35 +59,57 @@ public sealed class CompletionRules
/// <param name="dismissIfLastCharacterDeleted">True if the list should be dismissed when the user deletes the last character in the span.</param>
/// <param name="defaultCommitCharacters">The default set of typed characters that cause the selected item to be committed.</param>
/// <param name="defaultEnterKeyRule">The default rule that determines if the enter key is passed through to the editor after the selected item has been committed.</param>
/// <returns></returns>
public static CompletionRules Create(
bool dismissIfEmpty,
bool dismissIfLastCharacterDeleted,
ImmutableArray<char> defaultCommitCharacters,
EnterKeyRule defaultEnterKeyRule)
{
return Create(dismissIfEmpty, dismissIfLastCharacterDeleted, defaultCommitCharacters,
defaultEnterKeyRule, SnippetsRule.Default);
}
/// <summary>
/// Creates a new <see cref="CompletionRules"/> instance.
/// </summary>
/// <param name="dismissIfEmpty">True if the completion list should be dismissed if the user's typing causes it to filter and display no items.</param>
/// <param name="dismissIfLastCharacterDeleted">True if the list should be dismissed when the user deletes the last character in the span.</param>
/// <param name="defaultCommitCharacters">The default set of typed characters that cause the selected item to be committed.</param>
/// <param name="defaultEnterKeyRule">The default rule that determines if the enter key is passed through to the editor after the selected item has been committed.</param>
/// <param name="snippetsRule">The rule that controls snippets behavior.</param>
public static CompletionRules Create(
bool dismissIfEmpty = false,
bool dismissIfLastCharacterDeleted = false,
ImmutableArray<char> defaultCommitCharacters = default(ImmutableArray<char>),
EnterKeyRule defaultEnterKeyRule = EnterKeyRule.Default)
EnterKeyRule defaultEnterKeyRule = EnterKeyRule.Default,
SnippetsRule snippetsRule = SnippetsRule.Default)
{
return new CompletionRules(
dismissIfEmpty: dismissIfEmpty,
dismissIfLastCharacterDeleted: dismissIfLastCharacterDeleted,
defaultCommitCharacters: defaultCommitCharacters,
defaultEnterKeyRule: defaultEnterKeyRule);
defaultEnterKeyRule: defaultEnterKeyRule,
snippetsRule: snippetsRule);
}
private CompletionRules With(
Optional<bool> dismissIfEmpty = default(Optional<bool>),
Optional<bool> dismissIfLastCharacterDeleted = default(Optional<bool>),
Optional<ImmutableArray<char>> defaultCommitCharacters = default(Optional<ImmutableArray<char>>),
Optional<EnterKeyRule> defaultEnterKeyRule = default(Optional<EnterKeyRule>))
Optional<EnterKeyRule> defaultEnterKeyRule = default(Optional<EnterKeyRule>),
Optional<SnippetsRule> snippetsRule = default(Optional<SnippetsRule>))
{
var newDismissIfEmpty = dismissIfEmpty.HasValue ? dismissIfEmpty.Value : this.DismissIfEmpty;
var newDismissIfLastCharacterDeleted = dismissIfLastCharacterDeleted.HasValue ? dismissIfLastCharacterDeleted.Value : this.DismissIfLastCharacterDeleted;
var newDefaultCommitCharacters = defaultCommitCharacters.HasValue ? defaultCommitCharacters.Value : this.DefaultCommitCharacters;
var newDefaultEnterKeyRule = defaultEnterKeyRule.HasValue ? defaultEnterKeyRule.Value : this.DefaultEnterKeyRule;
var newSnippetsRule = snippetsRule.HasValue ? snippetsRule.Value : this.SnippetsRule;
if (newDismissIfEmpty == this.DismissIfEmpty
&& newDismissIfLastCharacterDeleted == this.DismissIfLastCharacterDeleted
&& newDefaultCommitCharacters == this.DefaultCommitCharacters
&& newDefaultEnterKeyRule == this.DefaultEnterKeyRule)
if (newDismissIfEmpty == this.DismissIfEmpty &&
newDismissIfLastCharacterDeleted == this.DismissIfLastCharacterDeleted &&
newDefaultCommitCharacters == this.DefaultCommitCharacters &&
newDefaultEnterKeyRule == this.DefaultEnterKeyRule &&
newSnippetsRule == this.SnippetsRule)
{
return this;
}
......@@ -90,7 +119,8 @@ public sealed class CompletionRules
newDismissIfEmpty,
newDismissIfLastCharacterDeleted,
newDefaultCommitCharacters,
newDefaultEnterKeyRule);
newDefaultEnterKeyRule,
newSnippetsRule);
}
}
......@@ -126,12 +156,18 @@ public CompletionRules WithDefaultEnterKeyRule(EnterKeyRule defaultEnterKeyRule)
return With(defaultEnterKeyRule: defaultEnterKeyRule);
}
private static readonly ImmutableArray<char> s_defaultCommitKeys = new[]
{
/// <summary>
/// Creates a copy of the this <see cref="CompletionRules"/> with the <see cref="SnippetsRule"/> property changed.
/// </summary>
public CompletionRules WithSnippetsRule(SnippetsRule snippetsRule)
{
return With(snippetsRule: snippetsRule);
}
private static readonly ImmutableArray<char> s_defaultCommitKeys = ImmutableArray.Create(
' ', '{', '}', '[', ']', '(', ')', '.', ',', ':',
';', '+', '-', '*', '/', '%', '&', '|', '^', '!',
'~', '=', '<', '>', '?', '@', '#', '\'', '\"', '\\'
}.ToImmutableArray();
'~', '=', '<', '>', '?', '@', '#', '\'', '\"', '\\');
/// <summary>
/// The default <see cref="CompletionRules"/> if none is otherwise specified.
......@@ -141,6 +177,7 @@ public CompletionRules WithDefaultEnterKeyRule(EnterKeyRule defaultEnterKeyRule)
dismissIfEmpty: false,
dismissIfLastCharacterDeleted: false,
defaultCommitCharacters: s_defaultCommitKeys,
defaultEnterKeyRule: EnterKeyRule.Never);
defaultEnterKeyRule: EnterKeyRule.Never,
snippetsRule: SnippetsRule.NeverInclude);
}
}
......@@ -137,16 +137,32 @@ protected ImmutableArray<CompletionProvider> GetProviders(ImmutableHashSet<strin
}
}
protected virtual ImmutableArray<CompletionProvider> GetProviders(ImmutableHashSet<string> roles, CompletionTrigger trigger)
protected virtual ImmutableArray<CompletionProvider> GetProviders(
ImmutableHashSet<string> roles, CompletionTrigger trigger)
{
if (trigger.Kind == CompletionTriggerKind.Snippets)
var snippetsRule = this.GetRules().SnippetsRule;
if (snippetsRule == SnippetsRule.NeverInclude)
{
return GetProviders(roles).Where(p => p.IsSnippetProvider).ToImmutableArray();
return GetProviders(roles).Where(p => !p.IsSnippetProvider).ToImmutableArray();
}
else
else if (snippetsRule == SnippetsRule.AlwaysInclude)
{
return GetProviders(roles);
}
else if (snippetsRule == SnippetsRule.IncludeAfterTypingIdentifierQuestionTab)
{
if (trigger.Kind == CompletionTriggerKind.Snippets)
{
return GetProviders(roles).Where(p => p.IsSnippetProvider).ToImmutableArray();
}
else
{
return GetProviders(roles).Where(p => !p.IsSnippetProvider).ToImmutableArray();
}
}
return ImmutableArray<CompletionProvider>.Empty;
}
internal protected CompletionProvider GetProvider(CompletionItem item)
......
......@@ -47,11 +47,6 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
var options = context.Options;
var cancellationToken = context.CancellationToken;
if (!options.GetOption(CompletionOptions.IncludeKeywords, document.Project.Language))
{
return;
}
using (Logger.LogBlock(FunctionId.Completion_KeywordCompletionProvider_GetItemsWorker, cancellationToken))
{
var keywords = await document.GetUnionItemsFromDocumentAndLinkedDocumentsAsync(
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Completion
{
public enum SnippetsRule
{
/// <summary>
/// Snippet triggering follows the default rules of the language.
/// </summary>
Default = 0,
/// <summary>
/// Snippets are never included in the completion list
/// </summary>
NeverInclude = 1,
/// <summary>
/// Snippets are always included in the completion list.
/// </summary>
AlwaysInclude = 2,
/// <summary>
/// Snippets are included if the user types: id?&lt;tab&gt;
/// </summary>
IncludeAfterTypingIdentifierQuestionTab = 3,
}
}
\ No newline at end of file
......@@ -200,6 +200,7 @@
<Compile Include="Completion\Providers\RecommendedKeyword.cs" />
<Compile Include="Completion\Providers\XmlDocCommentCompletionItem.cs" />
<Compile Include="Completion\SuggestionMode\SuggestionModeCompletionProvider.cs" />
<Compile Include="Completion\SnippetsRule.cs" />
<Compile Include="Diagnostics\AnalyzerHelper.cs" />
<Compile Include="Diagnostics\AbstractHostDiagnosticUpdateSource.cs" />
<Compile Include="Diagnostics\Analyzers\QualifyMemberAccessDiagnosticAnalyzerBase.cs" />
......
......@@ -80,10 +80,12 @@ Microsoft.CodeAnalysis.Completion.CompletionRules.DefaultCommitCharacters.get ->
Microsoft.CodeAnalysis.Completion.CompletionRules.DefaultEnterKeyRule.get -> Microsoft.CodeAnalysis.Completion.EnterKeyRule
Microsoft.CodeAnalysis.Completion.CompletionRules.DismissIfEmpty.get -> bool
Microsoft.CodeAnalysis.Completion.CompletionRules.DismissIfLastCharacterDeleted.get -> bool
Microsoft.CodeAnalysis.Completion.CompletionRules.SnippetsRule.get -> Microsoft.CodeAnalysis.Completion.SnippetsRule
Microsoft.CodeAnalysis.Completion.CompletionRules.WithDefaultCommitCharacters(System.Collections.Immutable.ImmutableArray<char> defaultCommitCharacters) -> Microsoft.CodeAnalysis.Completion.CompletionRules
Microsoft.CodeAnalysis.Completion.CompletionRules.WithDefaultEnterKeyRule(Microsoft.CodeAnalysis.Completion.EnterKeyRule defaultEnterKeyRule) -> Microsoft.CodeAnalysis.Completion.CompletionRules
Microsoft.CodeAnalysis.Completion.CompletionRules.WithDismissIfEmpty(bool dismissIfEmpty) -> Microsoft.CodeAnalysis.Completion.CompletionRules
Microsoft.CodeAnalysis.Completion.CompletionRules.WithDismissIfLastCharacterDeleted(bool dismissIfLastCharacterDeleted) -> Microsoft.CodeAnalysis.Completion.CompletionRules
Microsoft.CodeAnalysis.Completion.CompletionRules.WithSnippetsRule(Microsoft.CodeAnalysis.Completion.SnippetsRule snippetsRule) -> Microsoft.CodeAnalysis.Completion.CompletionRules
Microsoft.CodeAnalysis.Completion.CompletionService
Microsoft.CodeAnalysis.Completion.CompletionService.CompletionService() -> void
Microsoft.CodeAnalysis.Completion.CompletionServiceWithProviders
......@@ -111,6 +113,11 @@ Microsoft.CodeAnalysis.Completion.ExportCompletionProviderAttribute.Name.get ->
Microsoft.CodeAnalysis.Completion.ExportCompletionProviderAttribute.Roles.get -> string[]
Microsoft.CodeAnalysis.Completion.ExportCompletionProviderAttribute.Roles.set -> void
Microsoft.CodeAnalysis.Completion.MatchPriority
Microsoft.CodeAnalysis.Completion.SnippetsRule
Microsoft.CodeAnalysis.Completion.SnippetsRule.AlwaysInclude = 2 -> Microsoft.CodeAnalysis.Completion.SnippetsRule
Microsoft.CodeAnalysis.Completion.SnippetsRule.Default = 0 -> Microsoft.CodeAnalysis.Completion.SnippetsRule
Microsoft.CodeAnalysis.Completion.SnippetsRule.IncludeAfterTypingIdentifierQuestionTab = 3 -> Microsoft.CodeAnalysis.Completion.SnippetsRule
Microsoft.CodeAnalysis.Completion.SnippetsRule.NeverInclude = 1 -> Microsoft.CodeAnalysis.Completion.SnippetsRule
Microsoft.CodeAnalysis.TaggedText
Microsoft.CodeAnalysis.TaggedText.Tag.get -> string
Microsoft.CodeAnalysis.TaggedText.TaggedText(string tag, string text) -> void
......@@ -198,7 +205,8 @@ static Microsoft.CodeAnalysis.Completion.CompletionItemRules.Create(System.Colle
static Microsoft.CodeAnalysis.Completion.CompletionItemRules.Create(System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Completion.CharacterSetModificationRule> filterCharacterRules, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Completion.CharacterSetModificationRule> commitCharacterRules, Microsoft.CodeAnalysis.Completion.EnterKeyRule enterKeyRule, bool formatOnCommit, int? matchPriority) -> Microsoft.CodeAnalysis.Completion.CompletionItemRules
static Microsoft.CodeAnalysis.Completion.CompletionItemRules.Default -> Microsoft.CodeAnalysis.Completion.CompletionItemRules
static Microsoft.CodeAnalysis.Completion.CompletionList.Create(Microsoft.CodeAnalysis.Text.TextSpan defaultSpan, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Completion.CompletionItem> items, Microsoft.CodeAnalysis.Completion.CompletionRules rules = null, Microsoft.CodeAnalysis.Completion.CompletionItem suggestionModeItem = null) -> Microsoft.CodeAnalysis.Completion.CompletionList
static Microsoft.CodeAnalysis.Completion.CompletionRules.Create(bool dismissIfEmpty = false, bool dismissIfLastCharacterDeleted = false, System.Collections.Immutable.ImmutableArray<char> defaultCommitCharacters = default(System.Collections.Immutable.ImmutableArray<char>), Microsoft.CodeAnalysis.Completion.EnterKeyRule defaultEnterKeyRule = Microsoft.CodeAnalysis.Completion.EnterKeyRule.Default) -> Microsoft.CodeAnalysis.Completion.CompletionRules
static Microsoft.CodeAnalysis.Completion.CompletionRules.Create(bool dismissIfEmpty = false, bool dismissIfLastCharacterDeleted = false, System.Collections.Immutable.ImmutableArray<char> defaultCommitCharacters = default(System.Collections.Immutable.ImmutableArray<char>), Microsoft.CodeAnalysis.Completion.EnterKeyRule defaultEnterKeyRule = Microsoft.CodeAnalysis.Completion.EnterKeyRule.Default, Microsoft.CodeAnalysis.Completion.SnippetsRule snippetsRule = Microsoft.CodeAnalysis.Completion.SnippetsRule.Default) -> Microsoft.CodeAnalysis.Completion.CompletionRules
static Microsoft.CodeAnalysis.Completion.CompletionRules.Create(bool dismissIfEmpty, bool dismissIfLastCharacterDeleted, System.Collections.Immutable.ImmutableArray<char> defaultCommitCharacters, Microsoft.CodeAnalysis.Completion.EnterKeyRule defaultEnterKeyRule) -> Microsoft.CodeAnalysis.Completion.CompletionRules
static Microsoft.CodeAnalysis.Completion.CompletionService.GetService(Microsoft.CodeAnalysis.Document document) -> Microsoft.CodeAnalysis.Completion.CompletionService
static Microsoft.CodeAnalysis.Completion.CompletionTrigger.CreateDeletionTrigger(char deletedCharacter) -> Microsoft.CodeAnalysis.Completion.CompletionTrigger
static Microsoft.CodeAnalysis.Completion.CompletionTrigger.CreateInsertionTrigger(char insertedCharacter) -> Microsoft.CodeAnalysis.Completion.CompletionTrigger
......
......@@ -58,23 +58,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion
End Property
Private _latestRules As CompletionRules = CompletionRules.Create(
dismissIfEmpty:=True,
dismissIfLastCharacterDeleted:=True,
defaultCommitCharacters:=CompletionRules.Default.DefaultCommitCharacters,
defaultEnterKeyRule:=EnterKeyRule.Always)
dismissIfEmpty:=True,
dismissIfLastCharacterDeleted:=True,
defaultCommitCharacters:=CompletionRules.Default.DefaultCommitCharacters,
defaultEnterKeyRule:=EnterKeyRule.Always)
Public Overrides Function GetRules() As CompletionRules
Dim options = _workspace.Options
' Although EnterKeyBehavior is a per-language setting, the meaning of an unset setting (Default) differs between C# And VB
' In VB the default means Always to maintain previous behavior
Dim rule = options.GetOption(CompletionOptions.EnterKeyBehavior, LanguageNames.VisualBasic)
Dim enterRule = options.GetOption(CompletionOptions.EnterKeyBehavior, LanguageNames.VisualBasic)
Dim snippetsRule = options.GetOption(CompletionOptions.SnippetsBehavior, LanguageNames.VisualBasic)
If rule = EnterKeyRule.Default Then
rule = EnterKeyRule.Always
If enterRule = EnterKeyRule.Default Then
enterRule = EnterKeyRule.Always
End If
Dim newRules = _latestRules.WithDefaultEnterKeyRule(rule)
If snippetsRule = SnippetsRule.Default Then
snippetsRule = SnippetsRule.IncludeAfterTypingIdentifierQuestionTab
End If
Dim newRules = _latestRules.WithDefaultEnterKeyRule(enterRule).
WithSnippetsRule(snippetsRule)
Interlocked.Exchange(_latestRules, newRules)
......@@ -86,18 +92,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion
Return _completionProviders
End Function
Protected Overrides Function GetProviders(roles As ImmutableHashSet(Of String), trigger As CompletionTrigger) As ImmutableArray(Of CompletionProvider)
Dim _providers = MyBase.GetProviders(roles)
If trigger.Kind = CompletionTriggerKind.Snippets Then
_providers = _providers.Where(Function(p) p.IsSnippetProvider).ToImmutableArray()
Else
_providers = _providers.Where(Function(p) Not p.IsSnippetProvider).ToImmutableArray()
End If
Return _providers
End Function
Protected Overrides Function GetBetterItem(item As CompletionItem, existingItem As CompletionItem) As CompletionItem
' If one Is a keyword, And the other Is some other item that inserts the same text as the keyword,
' keep the keyword (VB only)
......
......@@ -402,6 +402,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Always include snippets.
/// </summary>
internal static string Option_Always_include_snippets {
get {
return ResourceManager.GetString("Option_Always_include_snippets", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Show completion list after a character is typed.
/// </summary>
......@@ -519,6 +528,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Include snippets when ?-Tab is typed after an identifier.
/// </summary>
internal static string Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier {
get {
return ResourceManager.GetString("Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Insert * at the start of new lines when writing /* */ comments.
/// </summary>
......@@ -537,6 +555,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Never include snippets.
/// </summary>
internal static string Option_Never_include_snippets {
get {
return ResourceManager.GetString("Option_Never_include_snippets", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Only add new line on enter after end of fully typed word.
/// </summary>
......@@ -852,6 +879,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Snippets behavior.
/// </summary>
internal static string Snippets_behavior {
get {
return ResourceManager.GetString("Snippets_behavior", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Insert space after cast.
/// </summary>
......
......@@ -468,10 +468,22 @@
<data name="Option_Only_add_new_line_on_enter_with_whole_word" xml:space="preserve">
<value>_Only add new line on enter after end of fully typed word</value>
</data>
<data name="Option_Always_add_new_line_on_enter" xml:space="preserve">
<data name="Option_Always_add_new_line_on_enter" xml:space="preserve">
<value>_Always add new line on enter</value>
</data>
<data name="Option_Never_add_new_line_on_enter" xml:space="preserve">
<data name="Option_Never_add_new_line_on_enter" xml:space="preserve">
<value>_Never add new line on enter</value>
</data>
<data name="Option_Always_include_snippets" xml:space="preserve">
<value>Always include snippets</value>
</data>
<data name="Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier" xml:space="preserve">
<value>Include snippets when ?-Tab is typed after an identifier</value>
</data>
<data name="Option_Never_include_snippets" xml:space="preserve">
<value>Never include snippets</value>
</data>
<data name="Snippets_behavior" xml:space="preserve">
<value>Snippets behavior</value>
</data>
</root>
\ No newline at end of file
......@@ -208,6 +208,12 @@ public int EnterKeyBehavior
set { SetOption(CompletionOptions.EnterKeyBehavior, (EnterKeyRule)value); }
}
public int SnippetsBehavior
{
get { return (int)GetOption(CompletionOptions.SnippetsBehavior); }
set { SetOption(CompletionOptions.SnippetsBehavior, (SnippetsRule)value); }
}
public int NewLines_AnonymousTypeInitializer_EachMember
{
get { return GetBooleanOption(CSharpFormattingOptions.NewLineForMembersInAnonymousTypes); }
......@@ -318,14 +324,14 @@ public int RenameTrackingPreview
public int ShowKeywords
{
get { return GetBooleanOption(CompletionOptions.IncludeKeywords); }
set { SetBooleanOption(CompletionOptions.IncludeKeywords, value); }
get { return 0; }
set { }
}
public int ShowSnippets
{
get { return GetBooleanOption(CSharpCompletionOptions.IncludeSnippets); }
set { SetBooleanOption(CSharpCompletionOptions.IncludeSnippets, value); }
get { return this.SnippetsBehavior; }
set { this.SnippetsBehavior = value; }
}
public int SortUsings_PlaceSystemFirst
......
......@@ -80,7 +80,6 @@ private bool ShouldIncludeOnOffOption(FieldInfo fieldInfo)
result.AddRange(new[]
{
new KeyValuePair<string, IOption>(GetStorageKeyForOption(CompletionOptions.IncludeKeywords), CompletionOptions.IncludeKeywords),
new KeyValuePair<string, IOption>(GetStorageKeyForOption(CompletionOptions.TriggerOnTypingLetters), CompletionOptions.TriggerOnTypingLetters),
new KeyValuePair<string, IOption>(GetStorageKeyForOption(CompletionOptions.ShowCompletionItemFilters), CompletionOptions.ShowCompletionItemFilters),
new KeyValuePair<string, IOption>(GetStorageKeyForOption(CompletionOptions.HighlightMatchingPortionsOfCompletionListItems), CompletionOptions.HighlightMatchingPortionsOfCompletionListItems),
......@@ -144,11 +143,11 @@ protected override bool SupportsOption(IOption option, string languageName)
}
else if (languageName == LanguageNames.CSharp)
{
if (option == CompletionOptions.IncludeKeywords ||
option == CompletionOptions.TriggerOnTypingLetters ||
if (option == CompletionOptions.TriggerOnTypingLetters ||
option == CompletionOptions.ShowCompletionItemFilters ||
option == CompletionOptions.HighlightMatchingPortionsOfCompletionListItems ||
option == CompletionOptions.EnterKeyBehavior ||
option == CompletionOptions.SnippetsBehavior ||
option.Feature == SimplificationOptions.PerLanguageFeatureName ||
option.Feature == ExtractMethodOptions.FeatureName ||
option.Feature == ServiceFeatureOnOffOptions.OptionName ||
......@@ -272,6 +271,11 @@ public override bool TryFetch(OptionKey optionKey, out object value)
return FetchEnterKeyBehavior(optionKey, out value);
}
if (optionKey.Option == CompletionOptions.SnippetsBehavior)
{
return FetchSnippetsBehavior(optionKey, out value);
}
return base.TryFetch(optionKey, out value);
}
......@@ -281,6 +285,45 @@ private bool FetchStyleBool(string settingName, out object value)
return FetchStyleOption<bool>(typeStyleValue, out value);
}
/// <summary>
/// The EnterKeyBehavior option (formerly AddNewLineOnEnterAfterFullyTypedWord) used to only exist in C# and as a boolean.
/// We need to maintain the meaning of the serialized legacy setting.
/// </summary>
private bool FetchSnippetsBehavior(OptionKey optionKey, out object value)
{
if (!base.TryFetch(optionKey, out value))
{
return false;
}
if (!value.Equals(SnippetsRule.Default))
{
return true;
}
// if the SnippetsBehavior setting cannot be loaded, then attempt to load and upgrade the legacy setting
#pragma warning disable CS0618 // IncludeSnippets is obsolete
if (base.TryFetch(CSharpCompletionOptions.IncludeSnippets, out value))
#pragma warning restore CS0618
{
if ((bool)value)
{
value = SnippetsRule.AlwaysInclude;
}
else
{
value = SnippetsRule.NeverInclude;
}
return true;
}
value = SnippetsRule.AlwaysInclude;
return true;
}
/// <summary>
/// The EnterKeyBehavior option (formerly AddNewLineOnEnterAfterFullyTypedWord) used to only exist in C# and as a boolean.
/// We need to maintain the meaning of the serialized legacy setting.
......
......@@ -17,17 +17,7 @@
<StackPanel>
<CheckBox x:Uid="BringUpOnIdentifier"
x:Name="BringUpOnIdentifier"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_BringUpOnIdentifier}"
Checked="BringUpOnIdentifier_Checked"
Unchecked="BringUpOnIdentifier_Unchecked" />
<StackPanel Margin="15, 0, 0, 0">
<CheckBox x:Uid="ShowKeywords"
x:Name="ShowKeywords"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_ShowKeywords}" />
<CheckBox x:Uid="ShowSnippets"
x:Name="ShowSnippets"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_ShowSnippets}" />
</StackPanel>
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_BringUpOnIdentifier}" />
<CheckBox x:Uid="Highlight_matching_portions_of_completion_list_items"
x:Name="Highlight_matching_portions_of_completion_list_items"
......@@ -36,6 +26,19 @@
x:Name="Show_completion_item_filters"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Show_completion_item_filters}" />
<Label Content="{x:Static local:IntelliSenseOptionPageStrings.Snippets_behavior}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Snippets_behavior"
x:Name="Never_include_snippets"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Never_include_snippets}"/>
<RadioButton GroupName="Snippets_behavior"
x:Name="Always_include_snippets"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Always_include_snippets}"/>
<RadioButton GroupName="Snippets_behavior"
x:Name="Include_snippets_when_question_Tab_is_typed_after_an_identifier"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier}"/>
</StackPanel>
<Label Content="{x:Static local:IntelliSenseOptionPageStrings.Enter_key_behavior_Title}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="InsertNewlineOnEnterRadio"
......
......@@ -16,28 +16,15 @@ public IntelliSenseOptionPageControl(IServiceProvider serviceProvider) : base(se
BindToOption(Show_completion_item_filters, CompletionOptions.ShowCompletionItemFilters, LanguageNames.CSharp);
BindToOption(Highlight_matching_portions_of_completion_list_items, CompletionOptions.HighlightMatchingPortionsOfCompletionListItems, LanguageNames.CSharp);
BindToOption(ShowSnippets, CSharpCompletionOptions.IncludeSnippets);
BindToOption(ShowKeywords, CompletionOptions.IncludeKeywords, LanguageNames.CSharp);
BindToOption(BringUpOnIdentifier, CompletionOptions.TriggerOnTypingLetters, LanguageNames.CSharp);
BindToOption(Never_include_snippets, CompletionOptions.SnippetsBehavior, SnippetsRule.NeverInclude, LanguageNames.CSharp);
BindToOption(Always_include_snippets, CompletionOptions.SnippetsBehavior, SnippetsRule.AlwaysInclude, LanguageNames.CSharp);
BindToOption(Include_snippets_when_question_Tab_is_typed_after_an_identifier, CompletionOptions.SnippetsBehavior, SnippetsRule.IncludeAfterTypingIdentifierQuestionTab, LanguageNames.CSharp);
BindToOption(Never_add_new_line_on_enter, CompletionOptions.EnterKeyBehavior, EnterKeyRule.Never, LanguageNames.CSharp);
BindToOption(Only_add_new_line_on_enter_with_whole_word, CompletionOptions.EnterKeyBehavior, EnterKeyRule.AfterFullyTypedWord, LanguageNames.CSharp);
BindToOption(Always_add_new_line_on_enter, CompletionOptions.EnterKeyBehavior, EnterKeyRule.Always, LanguageNames.CSharp);
}
private void BringUpOnIdentifier_Checked(object sender, System.Windows.RoutedEventArgs e)
{
ShowKeywords.IsEnabled = false;
ShowSnippets.IsEnabled = false;
ShowKeywords.IsChecked = true;
ShowSnippets.IsChecked = true;
}
private void BringUpOnIdentifier_Unchecked(object sender, System.Windows.RoutedEventArgs e)
{
ShowKeywords.IsEnabled = true;
ShowSnippets.IsEnabled = true;
}
}
}
......@@ -46,5 +46,17 @@ public static string Option_ShowSnippets
public static string Option_Always_add_new_line_on_enter =>
CSharpVSResources.Option_Always_add_new_line_on_enter;
public static string Snippets_behavior =>
CSharpVSResources.Snippets_behavior;
public static string Option_Never_include_snippets =>
CSharpVSResources.Option_Never_include_snippets;
public static string Option_Always_include_snippets =>
CSharpVSResources.Option_Always_include_snippets;
public static string Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier =>
CSharpVSResources.Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier;
}
}
......@@ -127,6 +127,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Always include snippets.
'''</summary>
Friend Shared ReadOnly Property Option_Always_include_snippets() As String
Get
Return ResourceManager.GetString("Option_Always_include_snippets", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Automatic _insertion of Interface and MustOverride members.
'''</summary>
......@@ -136,6 +145,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to _Show completion list after a character is typed.
'''</summary>
Friend Shared ReadOnly Property Option_BringUpOnIdentifier() As String
Get
Return ResourceManager.GetString("Option_BringUpOnIdentifier", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Enable full solution _analysis.
'''</summary>
......@@ -280,6 +298,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Include snippets when ?-Tab is typed after an identifier.
'''</summary>
Friend Shared ReadOnly Property Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier() As String
Get
Return ResourceManager.GetString("Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to _Navigate to Object Browser for symbols defined in metadata.
'''</summary>
......@@ -298,6 +325,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Never include snippets.
'''</summary>
Friend Shared ReadOnly Property Option_Never_include_snippets() As String
Get
Return ResourceManager.GetString("Option_Never_include_snippets", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to _Only add new line on enter after end of fully typed word.
'''</summary>
......@@ -486,5 +522,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
Return ResourceManager.GetString("QualifyPropertyAccessWithMe", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Snippets behavior.
'''</summary>
Friend Shared ReadOnly Property Snippets_behavior() As String
Get
Return ResourceManager.GetString("Snippets_behavior", resourceCulture)
End Get
End Property
End Class
End Namespace
......@@ -258,4 +258,19 @@
<data name="Option_Never_add_new_line_on_enter" xml:space="preserve">
<value>_Never add new line on enter</value>
</data>
<data name="Option_Always_include_snippets" xml:space="preserve">
<value>Always include snippets</value>
</data>
<data name="Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier" xml:space="preserve">
<value>Include snippets when ?-Tab is typed after an identifier</value>
</data>
<data name="Option_Never_include_snippets" xml:space="preserve">
<value>Never include snippets</value>
</data>
<data name="Snippets_behavior" xml:space="preserve">
<value>Snippets behavior</value>
</data>
<data name="Option_BringUpOnIdentifier" xml:space="preserve">
<value>_Show completion list after a character is typed</value>
</data>
</root>
\ No newline at end of file
......@@ -15,12 +15,30 @@
<GroupBox x:Uid="CompletionListsGroupBox"
Header="{x:Static local:IntelliSenseOptionPageStrings.Option_CompletionLists}">
<StackPanel>
<CheckBox x:Uid="BringUpOnIdentifier"
x:Name="BringUpOnIdentifier"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_BringUpOnIdentifier}" />
<CheckBox x:Uid="Highlight_matching_portions_of_completion_list_items"
x:Name="Highlight_matching_portions_of_completion_list_items"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Highlight_matching_portions_of_completion_list_items}" />
<CheckBox x:Uid="Show_completion_item_filters"
x:Name="Show_completion_item_filters"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Show_completion_item_filters}" />
<Label Content="{x:Static local:IntelliSenseOptionPageStrings.Snippets_behavior}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Snippets_behavior"
x:Name="Never_include_snippets"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Never_include_snippets}"/>
<RadioButton GroupName="Snippets_behavior"
x:Name="Always_include_snippets"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Always_include_snippets}"/>
<RadioButton GroupName="Snippets_behavior"
x:Name="Include_snippets_when_question_Tab_is_typed_after_an_identifier"
Content="{x:Static local:IntelliSenseOptionPageStrings.Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier}"/>
</StackPanel>
<Label Content="{x:Static local:IntelliSenseOptionPageStrings.Enter_key_behavior_Title}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="InsertNewlineOnEnterRadio"
......
......@@ -12,9 +12,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
MyBase.New(serviceProvider)
InitializeComponent()
BindToOption(BringUpOnIdentifier, CompletionOptions.TriggerOnTypingLetters, LanguageNames.VisualBasic)
BindToOption(Show_completion_item_filters, CompletionOptions.ShowCompletionItemFilters, LanguageNames.VisualBasic)
BindToOption(Highlight_matching_portions_of_completion_list_items, CompletionOptions.HighlightMatchingPortionsOfCompletionListItems, LanguageNames.VisualBasic)
BindToOption(Never_include_snippets, CompletionOptions.SnippetsBehavior, SnippetsRule.NeverInclude, LanguageNames.VisualBasic)
BindToOption(Always_include_snippets, CompletionOptions.SnippetsBehavior, SnippetsRule.AlwaysInclude, LanguageNames.VisualBasic)
BindToOption(Include_snippets_when_question_Tab_is_typed_after_an_identifier, CompletionOptions.SnippetsBehavior, SnippetsRule.IncludeAfterTypingIdentifierQuestionTab, LanguageNames.VisualBasic)
BindToOption(Never_add_new_line_on_enter, CompletionOptions.EnterKeyBehavior, EnterKeyRule.Never, LanguageNames.VisualBasic)
BindToOption(Only_add_new_line_on_enter_with_whole_word, CompletionOptions.EnterKeyBehavior, EnterKeyRule.AfterFullyTypedWord, LanguageNames.VisualBasic)
BindToOption(Always_add_new_line_on_enter, CompletionOptions.EnterKeyBehavior, EnterKeyRule.Always, LanguageNames.VisualBasic)
......
......@@ -22,5 +22,20 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Public ReadOnly Property Enter_key_behavior_Title As String =
BasicVSResources.Enter_key_behavior_Title
Public ReadOnly Property Option_BringUpOnIdentifier As String =
BasicVSResources.Option_BringUpOnIdentifier
Public ReadOnly Property Snippets_behavior As String =
BasicVSResources.Snippets_behavior
Public ReadOnly Property Option_Never_include_snippets As String =
BasicVSResources.Option_Never_include_snippets
Public ReadOnly Property Option_Always_include_snippets As String =
BasicVSResources.Option_Always_include_snippets
Public ReadOnly Property Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier As String =
BasicVSResources.Option_Include_snippets_when_question_Tab_is_typed_after_an_identifier
End Module
End Namespace
\ No newline at end of file
......@@ -88,7 +88,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Protected Overrides Function SupportsOption([option] As IOption, languageName As String) As Boolean
If [option].Name = CompletionOptions.EnterKeyBehavior.Name Then
Return True
ElseIf [option].Name = CompletionOptions.SnippetsBehavior.Name Then
Return True
ElseIf languageName = LanguageNames.VisualBasic Then
If [option].Feature = FeatureOnOffOptions.OptionName Then
Return [option].Name = FeatureOnOffOptions.PrettyListing.Name OrElse
......@@ -165,6 +166,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Return FetchEnterKeyBehavior(optionKey, value)
End If
If optionKey.Option Is CompletionOptions.SnippetsBehavior Then
Return FetchSnippetsBehavior(optionKey, value)
End If
Return MyBase.TryFetch(optionKey, value)
End Function
......@@ -180,6 +185,18 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Return False
End Function
Private Function FetchSnippetsBehavior(optionKey As OptionKey, ByRef value As Object) As Boolean
If MyBase.TryFetch(optionKey, value) Then
If value.Equals(SnippetsRule.Default) Then
value = SnippetsRule.IncludeAfterTypingIdentifierQuestionTab
End If
Return True
End If
Return False
End Function
Public Overrides Function TryPersist(optionKey As OptionKey, value As Object) As Boolean
If Me.Manager Is Nothing Then
Debug.Fail("Manager is unexpectedly Nothing")
......
......@@ -6,7 +6,6 @@ Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Editor
Imports Microsoft.CodeAnalysis.Editor.Shared.Extensions
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports Microsoft.CodeAnalysis.Snippets
......@@ -82,8 +81,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets
Public Sub Commit(completionItem As CompletionItem, textView As ITextView, subjectBuffer As ITextBuffer, triggerSnapshot As ITextSnapshot, commitChar As Char?) Implements ICustomCommitCompletionProvider.Commit
Dim snippetClient = SnippetExpansionClient.GetSnippetExpansionClient(textView, subjectBuffer, _editorAdaptersFactoryService)
Dim caretPoint = textView.GetCaretPoint(subjectBuffer)
Dim trackingSpan = triggerSnapshot.CreateTrackingSpan(completionItem.Span.ToSpan(), SpanTrackingMode.EdgeInclusive)
Dim currentSpan = trackingSpan.GetSpan(subjectBuffer.CurrentSnapshot)
......@@ -93,4 +90,4 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets
snippetClient.TryInsertExpansion(updatedSpan.Start, updatedSpan.Start + completionItem.DisplayText.Length)
End Sub
End Class
End Namespace
End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册