public override async Task ProduceCompletionListAsync(CompletionListContext context) { var document = context.Document; var position = context.Position; var cancellationToken = context.CancellationToken; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (syntaxTree.IsInNonUserCode(position, cancellationToken)) { return; } var token = syntaxTree .FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position); if (!token.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.CommaToken)) { return; } var argumentList = token.Parent as BaseArgumentListSyntax; if (argumentList == null) { return; } var semanticModel = await document.GetSemanticModelForNodeAsync(argumentList, cancellationToken).ConfigureAwait(false); var parameterLists = GetParameterLists(semanticModel, position, argumentList.Parent, cancellationToken); if (parameterLists == null) { return; } var existingNamedParameters = GetExistingNamedParameters(argumentList, position); parameterLists = parameterLists.Where(pl => IsValid(pl, existingNamedParameters)); var unspecifiedParameters = parameterLists.SelectMany(pl => pl) .Where(p => !existingNamedParameters.Contains(p.Name)) .Distinct(this); if (!unspecifiedParameters.Any()) { return; } if (token.IsMandatoryNamedParameterPosition()) { context.MakeExclusive(true); } var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var filterSpan = CompletionUtilities.GetTextChangeSpan(text, position); var workspace = document.Project.Solution.Workspace; foreach (var parameter in unspecifiedParameters) { // Note: the filter text does not include the ':'. We want to ensure that if // the user types the name exactly (up to the colon) that it is selected as an // exact match. var escapedName = parameter.Name.ToIdentifierToken().ToString(); context.AddItem(new CompletionItem( this, escapedName + ColonString, filterSpan, CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, token.SpanStart, parameter), parameter.GetGlyph(), sortText: parameter.Name, filterText: escapedName, rules: ItemRules.Instance)); } }
protected override async Task <IEnumerable <CompletionItem> > GetItemsWorkerAsync( Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return(null); } var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); if (token.IsMandatoryNamedParameterPosition()) { return(null); } var typeInferenceService = document.GetLanguageService <ITypeInferenceService>(); var span = new TextSpan(position, 0); var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); var type = typeInferenceService.InferType(semanticModel, position, objectAsDefault: true, cancellationToken: cancellationToken); // If we have a Nullable<T>, unwrap it. if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { type = type.GetTypeArguments().FirstOrDefault(); if (type == null) { return(null); } } if (type.TypeKind != TypeKind.Enum) { type = GetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation); if (type == null) { return(null); } } if (!type.IsEditorBrowsable(document.ShouldHideAdvancedMembers(), semanticModel.Compilation)) { return(null); } // Does type have any aliases? ISymbol alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false); var displayService = document.GetLanguageService <ISymbolDisplayService>(); var displayText = alias != null ? alias.Name : displayService.ToMinimalDisplayString(semanticModel, position, type); var workspace = document.Project.Solution.Workspace; var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position); var item = new CSharpCompletionItem( workspace, this, displayText: displayText, filterSpan: textChangeSpan, descriptionFactory: CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, position, alias ?? type), glyph: (alias ?? type).GetGlyph(), preselect: true); return(SpecializedCollections.SingletonEnumerable(item)); }
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options) { // Bring up on space or at the start of a word, or after a ( or [. // // Note: we don't want to bring this up after traditional enum operators like & or |. // That's because we don't like the experience where the enum appears directly after the // operator. Instead, the user normally types <space> and we will bring up the list // then. var ch = text[characterPosition]; return (ch == ' ' || ch == '[' || ch == '(' || ch == '~' || (options.GetOption(CompletionOptions.TriggerOnTypingLetters, LanguageNames.CSharp) && CompletionUtilities.IsStartingNewWord(text, characterPosition))); }
public override bool IsInsertionTrigger(SourceText text, int insertedCharacterPosition, CompletionOptions options) => CompletionUtilities.IsTriggerAfterSpaceOrStartOfWordCharacter(text, insertedCharacterPosition, options);
public override bool IsCommitCharacter(CompletionItem completionItem, char ch, string textTypedSoFar) { return(CompletionUtilities.IsCommitCharacter(completionItem, ch, textTypedSoFar)); }
protected override int GetTargetCaretPosition(SyntaxNode caretTarget) { var methodDeclaration = (MethodDeclarationSyntax)caretTarget; return(CompletionUtilities.GetTargetCaretPositionForMethod(methodDeclaration)); }
public override bool IsTriggerCharacter(SourceText text, int characterPosition, OptionSet options) { return(CompletionUtilities.IsTriggerAfterSpaceOrStartOfWordCharacter(text, characterPosition, options)); }
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options) { return CompletionUtilities.IsTriggerAfterSpaceOrStartOfWordCharacter(text, characterPosition, options); }
public override bool IsInsertionTrigger(SourceText text, int characterPosition, CompletionOptions options) => CompletionUtilities.IsTriggerCharacter(text, characterPosition, options) || text[characterPosition] == ' ';
protected override TextSpan GetTextChangeSpan(SourceText text, int position) { // We can just defer to the standard text span algorithm. return(CompletionUtilities.GetTextChangeSpan(text, position)); }
private TextSpan GetTextChangeSpan(SourceText text, int position) { return(CompletionUtilities.GetTextChangeSpan(text, position)); }
/// <summary> /// Gets the dot-like token we're after, and also the start of the expression we'd want to place any text before. /// </summary> private static (SyntaxToken dotLikeToken, int expressionStart) GetDotAndExpressionStart(SyntaxNode root, int position, CancellationToken cancellationToken) { if (CompletionUtilities.GetDotTokenLeftOfPosition(root.SyntaxTree, position, cancellationToken) is not SyntaxToken dotToken) { return(default);
public override bool IsInsertionTrigger(SourceText text, int characterPosition, CompletionOptions options) => text[characterPosition] == ' ' || options.TriggerOnTypingLetters && CompletionUtilities.IsStartingNewWord(text, characterPosition);
private async Task <CompletionItem> GetBuilderAsync(Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken = default(CancellationToken)) { if (triggerInfo.TriggerReason == CompletionTriggerReason.TypeCharCommand) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); if (triggerInfo.IsDebugger) { // Aggressive Intellisense in the debugger: always show the builder return(new CompletionItem(this, "", CompletionUtilities.GetTextChangeSpan(text, position), isBuilder: true)); } var tree = await document.GetCSharpSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); token = token.GetPreviousTokenIfTouchingWord(position); if (token.Kind() == SyntaxKind.None) { return(null); } var semanticModel = await document.GetCSharpSemanticModelForNodeAsync(token.Parent, cancellationToken).ConfigureAwait(false); var typeInferrer = document.GetLanguageService <ITypeInferenceService>(); if (IsLambdaExpression(semanticModel, position, token, typeInferrer, cancellationToken)) { return(new CompletionItem(this, CSharpFeaturesResources.LambdaExpression, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPotentialLambdaDeclaration.ToSymbolDisplayParts(), isBuilder: true)); } else if (IsAnonymousObjectCreation(token)) { return(new CompletionItem(this, CSharpFeaturesResources.MemberName, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPossibleExplicitlyNamesAnonTypeMemCreation.ToSymbolDisplayParts(), isBuilder: true)); } else if (token.IsPreProcessorExpressionContext()) { return(new CompletionItem(this, "", CompletionUtilities.GetTextChangeSpan(text, position), isBuilder: true)); } else if (IsImplicitArrayCreation(semanticModel, token, position, typeInferrer, cancellationToken)) { return(new CompletionItem(this, CSharpFeaturesResources.ImplicitArrayCreation, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPotentialImplicitArray.ToSymbolDisplayParts(), isBuilder: true)); } else { return(token.IsKindOrHasMatchingText(SyntaxKind.FromKeyword) || token.IsKindOrHasMatchingText(SyntaxKind.JoinKeyword) ? new CompletionItem(this, CSharpFeaturesResources.RangeVariable, CompletionUtilities.GetTextChangeSpan(text, position), CSharpFeaturesResources.AutoselectDisabledDueToPotentialRangeVariableDecl.ToSymbolDisplayParts(), isBuilder: true) : null); } } return(null); }
public override async Task ProduceCompletionListAsync(CompletionListContext context) { try { var document = context.Document; var position = context.Position; var options = context.Options; var cancellationToken = context.CancellationToken; var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree.IsInNonUserCode(position, cancellationToken)) { return; } var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken); if (token.IsMandatoryNamedParameterPosition()) { return; } var typeInferenceService = document.GetLanguageService <ITypeInferenceService>(); var span = new TextSpan(position, 0); var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); var type = typeInferenceService.InferType(semanticModel, position, objectAsDefault: true, cancellationToken: cancellationToken); // If we have a Nullable<T>, unwrap it. if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { type = type.GetTypeArguments().FirstOrDefault(); if (type == null) { return; } } if (type.TypeKind != TypeKind.Enum) { type = GetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation); if (type == null) { return; } } if (!type.IsEditorBrowsable(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation)) { return; } // Does type have any aliases? ISymbol alias = await type.FindApplicableAlias(position, semanticModel, cancellationToken).ConfigureAwait(false); var displayService = document.GetLanguageService <ISymbolDisplayService>(); var displayText = alias != null ? alias.Name : displayService.ToMinimalDisplayString(semanticModel, position, type); var workspace = document.Project.Solution.Workspace; var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position); var item = new CompletionItem( this, displayText: displayText, filterSpan: textChangeSpan, descriptionFactory: CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, position, alias ?? type), glyph: (alias ?? type).GetGlyph(), preselect: true, rules: ItemRules.Instance); context.AddItem(item); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
internal override TextSpan GetCurrentSpan(TextSpan span, SourceText text) { return(CompletionUtilities.GetCompletionItemSpan(text, span.End)); }
protected override bool ShouldTriggerAfterQuotes(SourceText text, int insertedCharacterPosition) => CompletionUtilities.IsStartingNewWord(text, insertedCharacterPosition);
protected override TextSpan GetTextChangeSpan(SourceText text, int position) { return(CompletionUtilities.GetTextChangeSpan(text, position)); }
protected override async Task <IEnumerable <CompletionItem> > GetItemsWorkerAsync( Document document, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (syntaxTree.IsInNonUserCode(position, cancellationToken)) { return(null); } var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken); token = token.GetPreviousTokenIfTouchingWord(position); if (token.Kind() != SyntaxKind.OpenParenToken && token.Kind() != SyntaxKind.OpenBracketToken && token.Kind() != SyntaxKind.CommaToken) { return(null); } var argumentList = token.Parent as BaseArgumentListSyntax; if (argumentList == null) { return(null); } var semanticModel = await document.GetSemanticModelForNodeAsync(argumentList, cancellationToken).ConfigureAwait(false); var parameterLists = GetParameterLists(semanticModel, position, argumentList.Parent, cancellationToken); if (parameterLists == null) { return(null); } var existingNamedParameters = GetExistingNamedParameters(argumentList, position); parameterLists = parameterLists.Where(pl => IsValid(pl, existingNamedParameters)); var unspecifiedParameters = parameterLists.SelectMany(pl => pl) .Where(p => !existingNamedParameters.Contains(p.Name)) .Distinct(this); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); return(unspecifiedParameters.Select( p => { // Note: the filter text does not include the ':'. We want to ensure that if // the user types the name exactly (up to the colon) that it is selected as an // exact match. var workspace = document.Project.Solution.Workspace; var escaped = p.Name.ToIdentifierToken().ToString(); return new CompletionItem( this, escaped + ColonString, CompletionUtilities.GetTextChangeSpan(text, position), CommonCompletionUtilities.CreateDescriptionFactory(workspace, semanticModel, token.SpanStart, p), p.GetGlyph(), sortText: p.Name, filterText: escaped, rules: ItemRules.Instance); })); }
public override bool SendEnterThroughToEditor(CompletionItem completionItem, string textTypedSoFar) { return(CompletionUtilities.SendEnterThroughToEditor(completionItem, textTypedSoFar)); }
public override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options) { var c = text[characterPosition]; return(c == '<' || c == '"' || CompletionUtilities.IsTriggerAfterSpaceOrStartOfWordCharacter(text, characterPosition, options)); }
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options) { var ch = text[characterPosition]; return(ch == ' ' || (CompletionUtilities.IsStartingNewWord(text, characterPosition) && options.GetOption(CompletionOptions.TriggerOnTypingLetters2, LanguageNames.CSharp))); }
public override bool IsTriggerCharacter(SourceText text, int characterPosition, OptionSet options) { return(CompletionUtilities.IsTriggerCharacter(text, characterPosition, options) || text[characterPosition] == ' '); }
internal override bool IsInsertionTrigger(SourceText text, int characterPosition, OptionSet options) { return(CompletionUtilities.IsTriggerCharacter(text, characterPosition, options)); }
private async Task <IEnumerable <CompletionItem> > GetCompletionsOffOfExplicitInterfaceAsync( Document document, SemanticModel semanticModel, int position, NameSyntax name, CancellationToken cancellationToken) { // Bind the interface name which is to the left of the dot var syntaxTree = semanticModel.SyntaxTree; var nameBinding = semanticModel.GetSymbolInfo(name, cancellationToken); var context = CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken); var symbol = nameBinding.Symbol as ITypeSymbol; if (symbol == null || symbol.TypeKind != TypeKind.Interface) { return(SpecializedCollections.EmptyEnumerable <CompletionItem>()); } var members = semanticModel.LookupSymbols( position: name.SpanStart, container: symbol) .Where(s => !s.IsStatic) .FilterToVisibleAndBrowsableSymbols(document.ShouldHideAdvancedMembers(), semanticModel.Compilation); // We're going to create a entry for each one, including the signature var completions = new List <CompletionItem>(); var signatureDisplayFormat = new SymbolDisplayFormat( genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, memberOptions: SymbolDisplayMemberOptions.IncludeParameters, parameterOptions: SymbolDisplayParameterOptions.IncludeName | SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | SymbolDisplayMiscellaneousOptions.UseSpecialTypes); var namePosition = name.SpanStart; var text = await context.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, context.Position); foreach (var member in members) { var displayString = member.ToMinimalDisplayString(semanticModel, namePosition, signatureDisplayFormat); var memberCopied = member; var insertionText = displayString; completions.Add(new SymbolCompletionItem( this, displayString, insertionText: insertionText, filterSpan: textChangeSpan, position: position, symbols: new List <ISymbol> { member }, context: context, rules: ItemRules.Instance)); } return(completions); }
public override bool IsInsertionTrigger( SourceText text, int characterPosition, OptionSet options ) => CompletionUtilities.IsTriggerCharacter(text, characterPosition, options);
public override async Task ProduceCompletionListAsync(CompletionListContext context) { var document = context.Document; var position = context.Position; var options = context.Options; var cancellationToken = context.CancellationToken; var span = new TextSpan(position, length: 0); var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); var syntaxTree = semanticModel.SyntaxTree; var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var semanticFacts = document.GetLanguageService <ISemanticFactsService>(); if (syntaxFacts.IsInNonUserCode(syntaxTree, position, cancellationToken) || semanticFacts.IsPreProcessorDirectiveContext(semanticModel, position, cancellationToken)) { return; } if (!syntaxTree.IsRightOfDotOrArrowOrColonColon(position, cancellationToken)) { return; } var node = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken) .GetPreviousTokenIfTouchingWord(position) .Parent; if (node.Kind() != SyntaxKind.ExplicitInterfaceSpecifier) { return; } // Bind the interface name which is to the left of the dot var name = ((ExplicitInterfaceSpecifierSyntax)node).Name; var symbol = semanticModel.GetSymbolInfo(name, cancellationToken).Symbol as ITypeSymbol; if (symbol?.TypeKind != TypeKind.Interface) { return; } var members = semanticModel.LookupSymbols( position: name.SpanStart, container: symbol) .Where(s => !s.IsStatic) .FilterToVisibleAndBrowsableSymbols(options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language), semanticModel.Compilation); // We're going to create a entry for each one, including the signature var namePosition = name.SpanStart; var text = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false); var textChangeSpan = CompletionUtilities.GetTextChangeSpan(text, position); foreach (var member in members) { var displayText = member.ToMinimalDisplayString(semanticModel, namePosition, s_signatureDisplayFormat); var insertionText = displayText; context.AddItem(new SymbolCompletionItem( this, displayText, insertionText: insertionText, filterSpan: textChangeSpan, position: position, symbols: new List <ISymbol> { member }, context: CSharpSyntaxContext.CreateContext(document.Project.Solution.Workspace, semanticModel, position, cancellationToken), rules: ItemRules.Instance)); } }