簡體   English   中英

Roslyn CodeFixProvider:應用代碼修復后移動插入符號

[英]Roslyn CodeFixProvider: Move caret after applying code fix

我實現了一個自定義CodeFixProvider,它向成員添加了一些XML文檔。

例:

public void MyMethod() { }

將被轉換為

/// <summary></summary>
public void MyMethod() { }

CodeFixProvider的實現如下:

public class MyCodeFixProvider : CodeFixProvider
{
  ...

  public async override Task RegisterCodeFixesAsync(CodeFixContext context)
  {
    await Task.Run(() =>
      {
        Diagnostics diagnostics = context.Diagnostics.First();
        CodeAction codeFix = CodeAction.Create("Title", c => CreateXmlDocs(...));

        context.RegisterCodeFix(codeFix, diagnostics);
      }
    ).ConfigureAwait(false);
  }

  ...
}

一切都按預期進行。

現在,我想添加一些額外的功能:應用代碼修復后,插入符號應移至空的Summary標簽內。

我發現Microsoft.CodeAnalysis.Features NuGet包中包含的DocumentNavigationOperation類。 此類應能夠將插入符號移動到指定位置。 但是我找不到任何有關如何使用此類的說明。 如果我從CreateXmlDocs方法內部調用它,則會引發異常:

Navigation must be performed on the foreground thread.

碼:

private static async Task<Solution> CreateXmlDocs()
{
  ...

  new DocumentNavigationOperation(newDocument.Id, 42)
    .Apply(newDocument.Project.Solution.Workspace, cancellationToken);

  ...
}

我不確定在CreateXmlDocs方法中使用此類是否有意義,因為在調用DocumentNavigationOperation時,Visual Studio尚未應用在此方法中創建的新解決方案。

有人知道在應用代碼修復后移動插入符號的解決方案嗎?

好的,與此同時我找到了解決方案。

需要自定義CodeAction才能使其正常工作:

internal class NavigateAfterCodeChangeAction : CodeAction
{

  private readonly Func<CancellationToken, Task<Solution>> codeChangeOperation;

  private readonly Func<Solution, CancellationToken, Task<NavigationTarget>> navigationTargetCalculation;

  public NavigateAfterCodeChangeAction(
    string title,
    Func<CancellationToken, Task<Solution>> codeChangeOperation,
    Func<Solution, CancellationToken, Task<NavigationTarget>> navigationTargetCalculation)
  {
    this.Title = title;
    this.codeChangeOperation = codeChangeOperation;
    this.navigationTargetCalculation = navigationTargetCalculation;
  }

  public override string Title { get; }

  protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
  {
    var operations = new List<CodeActionOperation>();
    Solution changedSolution = await this.codeChangeOperation(cancellationToken);
    NavigationTarget navigationTarget = await this.navigationTargetCalculation(changedSolution, cancellationToken);

    operations.Add(new ApplyChangesOperation(changedSolution));

    if (navigationTarget != null)
    {
      operations.Add(new DocumentNavigationOperation(navigationTarget.DocumentId, navigationTarget.Position));
    }

    return operations;
  }
}

internal class NavigationTarget
{

  public NavigationTarget(DocumentId documentId, int position)
  {
    this.DocumentId = documentId;
    this.Position = position;
  }

  public DocumentId DocumentId { get; }

  public int Position { get; }

}

CodeAction可以在使用CodeFixProvider代替CodeAction.Create()

public class MyCodeFixProvider : CodeFixProvider
{
  ...

  public async override Task RegisterCodeFixesAsync(CodeFixContext context)
  {
    await Task.Run(() =>
      {
        Diagnostics diagnostics = context.Diagnostics.First();
        CodeAction codeFix = new NavigateAfterCodeChangeAction(
          "Title",
          c => CreateXmlDocs(...)
          (s, c) => CalculateNavigationTarget(context.Document));

        context.RegisterCodeFix(codeFix, diagnostics);
      }
    ).ConfigureAwait(false);
  }

  private static NavigationTarget CalculateNavigationTarget(Document doc)
  {
    // Calculate the navigation target here...

    // Example: Navigate to position 42 of the document
    return new NavigationTarget(doc.Id, 42);
  }

  ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM