| File: BraceCompletion\InterpolatedStringBraceCompletionService.cs | Web Access |
| Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Composition; using System.Threading; using Microsoft.CodeAnalysis.BraceCompletion; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.BraceCompletion; /// <summary> /// Brace completion service for double quotes marking an interpolated string. Note that the <see /// cref="StringLiteralBraceCompletionService"/> is used for other double quote completions. /// </summary> [ExportBraceCompletionService(LanguageNames.CSharp), Shared] [method: ImportingConstructor] [method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] internal sealed class InterpolatedStringBraceCompletionService() : AbstractCSharpBraceCompletionService { protected override char OpeningBrace => DoubleQuote.OpenCharacter; protected override char ClosingBrace => DoubleQuote.CloseCharacter; public override bool AllowOverType(BraceCompletionContext context, CancellationToken cancellationToken) => AllowOverTypeWithValidClosingToken(context); /// <summary> /// Only return this service as valid when we're starting an interpolated string. Otherwise double quotes should be /// completed using the <see cref="StringLiteralBraceCompletionService"/> /// </summary> public override bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken) => OpeningBrace == brace && IsPositionInInterpolatedStringContext(document, openingPosition, cancellationToken); protected override bool IsValidOpeningBraceToken(SyntaxToken leftToken) => leftToken.Kind() is SyntaxKind.InterpolatedStringStartToken or SyntaxKind.InterpolatedVerbatimStringStartToken; protected override bool IsValidClosingBraceToken(SyntaxToken rightToken) => rightToken.IsKind(SyntaxKind.InterpolatedStringEndToken); protected override bool IsValidOpenBraceTokenAtPosition(SourceText text, SyntaxToken token, int position) => IsValidOpeningBraceToken(token) && token.Span.End - 1 == position; /// <summary> /// Returns true when the input position could be starting an interpolated string if opening quotes were typed. /// </summary> public static bool IsPositionInInterpolatedStringContext(ParsedDocument document, int position, CancellationToken cancellationToken) { var text = document.Text; var start = position - 1; if (start < 0) return false; // Check if the user is typing an interpolated or interpolated verbatim string. // If the preceding character(s) are not '$' or '$@' then we can't be starting an interpolated string. if (text[start] == '@') { // must have $@ for an interpolated string. otherwise this is some other @ construct. if (start == 0 || text[start - 1] != '$') return false; start--; } else if (text[start] == '$') { // could be @$ if (start > 0 && text[start - 1] == '@') start--; } else { return false; } return IsLegalExpressionLocation(document.SyntaxTree, start, cancellationToken); } }