|
// 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.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Indentation;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.BraceCompletion;
internal interface IBraceCompletionService
{
/// <summary>
/// Checks if this brace completion service should be the service used to provide brace completions at
/// the specified position with the specified opening brace.
///
/// Only one implementation of <see cref="IBraceCompletionService"/> should return true
/// for a given brace, opening position, and document. Only that service will be asked
/// for brace completion results.
/// </summary>
/// <param name="brace">
/// The opening brace character to be inserted at the opening position.</param>
/// <param name="openingPosition">
/// The opening position to insert the brace.
/// Note that the brace is not yet inserted at this position in the document.
/// </param>
/// <param name="document">The document to insert the brace at the position.</param>
/// <param name="cancellationToken">A cancellation token.</param>
bool CanProvideBraceCompletion(char brace, int openingPosition, ParsedDocument document, CancellationToken cancellationToken);
/// <summary>
/// True if <see cref="BraceCompletionResult"/> is available in the given <paramref name="context"/>.
/// Completes synchronously unless the service needs Semantic Model to determine the brace completion result.
/// </summary>
ValueTask<bool> HasBraceCompletionAsync(BraceCompletionContext context, Document document, CancellationToken cancellationToken);
/// <summary>
/// Returns the text change to add the closing brace given the context.
/// </summary>
BraceCompletionResult GetBraceCompletion(BraceCompletionContext braceCompletionContext);
/// <summary>
/// Returns any text changes that need to be made after adding the closing brace.
/// </summary>
/// <remarks>
/// This cannot be merged with <see cref="GetBraceCompletion(BraceCompletionContext)"/>
/// as we need to swap the editor tracking mode of the closing point from positive to negative
/// in BraceCompletionSessionProvider.BraceCompletionSession.Start after completing the brace and before
/// doing any kind of formatting on it. So these must be two distinct steps until we fully move to LSP.
/// </remarks>
BraceCompletionResult? GetTextChangesAfterCompletion(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken);
/// <summary>
/// Get any text changes that should be applied after the enter key is typed inside a brace completion context.
/// </summary>
BraceCompletionResult? GetTextChangeAfterReturn(BraceCompletionContext braceCompletionContext, IndentationOptions options, CancellationToken cancellationToken);
/// <summary>
/// Returns the brace completion context if the caret is located between an already completed
/// set of braces with only whitespace in between.
/// </summary>
BraceCompletionContext? GetCompletedBraceContext(ParsedDocument document, StructuredAnalyzerConfigOptions fallbackOptions, int caretLocation);
/// <summary>
/// Returns true if over typing should be allowed given the caret location and completed pair of braces.
/// For example some providers allow over typing in non-user code and others do not.
/// </summary>
bool AllowOverType(BraceCompletionContext braceCompletionContext, CancellationToken cancellationToken);
}
internal readonly struct BraceCompletionResult(ImmutableArray<TextChange> textChanges, LinePosition caretLocation)
{
/// <summary>
/// The set of text changes that should be applied to the input text to retrieve the
/// brace completion result.
/// </summary>
public ImmutableArray<TextChange> TextChanges { get; } = textChanges;
/// <summary>
/// The caret location in the new text created by applying all <see cref="TextChanges"/>
/// to the input text. Note the column in the line position can be virtual in that it points
/// to a location in the line which does not actually contain whitespace.
/// Hosts can determine how best to handle that virtual location.
/// For example, placing the character in virtual space (when suppported)
/// or inserting an appropriate number of spaces into the document".
/// </summary>
public LinePosition CaretLocation { get; } = caretLocation;
}
internal readonly struct BraceCompletionContext(ParsedDocument document, StructuredAnalyzerConfigOptions fallbackOptions, int openingPoint, int closingPoint, int caretLocation)
{
public ParsedDocument Document { get; } = document;
public StructuredAnalyzerConfigOptions FallbackOptions { get; } = fallbackOptions;
public int OpeningPoint { get; } = openingPoint;
public int ClosingPoint { get; } = closingPoint;
public int CaretLocation { get; } = caretLocation;
public bool HasCompletionForOpeningBrace(char openingBrace)
=> ClosingPoint >= 1 && Document.Text[OpeningPoint] == openingBrace;
public SyntaxToken GetOpeningToken()
=> Document.Root.FindToken(OpeningPoint, findInsideTrivia: true);
}
|