|
// 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.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Rename;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Editor.Xaml.Features.InlineRename
{
[ExportLanguageService(typeof(IEditorInlineRenameService), StringConstants.XamlLanguageName), Shared]
internal class XamlEditorInlineRenameService : IEditorInlineRenameService
{
private readonly IXamlRenameInfoService _renameService;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public XamlEditorInlineRenameService(IXamlRenameInfoService renameService)
{
_renameService = renameService;
}
public bool IsEnabled => true;
public Task<ImmutableDictionary<string, ImmutableArray<(string filePath, string content)>>> GetRenameContextAsync(IInlineRenameInfo inlineRenameInfo, IInlineRenameLocationSet inlineRenameLocationSet, CancellationToken cancellationToken)
{
return Task.FromResult(ImmutableDictionary<string, ImmutableArray<(string filePath, string content)>>.Empty);
}
public async Task<IInlineRenameInfo> GetRenameInfoAsync(Document document, int position, CancellationToken cancellationToken)
{
var renameInfo = await _renameService.GetRenameInfoAsync(document, position, cancellationToken).ConfigureAwait(false);
return new InlineRenameInfo(document, renameInfo);
}
private class InlineRenameInfo : IInlineRenameInfo
{
private readonly Document _document;
private readonly IXamlRenameInfo _renameInfo;
public InlineRenameInfo(Document document, IXamlRenameInfo renameInfo)
{
_document = document;
_renameInfo = renameInfo;
}
public bool CanRename => _renameInfo.CanRename;
public string DisplayName => _renameInfo.DisplayName;
public string FullDisplayName => _renameInfo.FullDisplayName;
public Glyph Glyph => InlineRenameInfo.FromSymbolKind(_renameInfo.Kind);
public bool HasOverloads => false;
public bool MustRenameOverloads => false;
public string LocalizedErrorMessage => _renameInfo.LocalizedErrorMessage;
public TextSpan TriggerSpan => _renameInfo.TriggerSpan;
// This property isn't currently supported in XAML since it would involve modifying the IXamlRenameInfo interface.
public ImmutableArray<CodeAnalysis.DocumentSpan> DefinitionLocations => default;
public async Task<IInlineRenameLocationSet> FindRenameLocationsAsync(SymbolRenameOptions options, CancellationToken cancellationToken)
{
var references = new List<InlineRenameLocation>();
var renameLocations = await _renameInfo.FindRenameLocationsAsync(
renameInStrings: options.RenameInStrings,
renameInComments: options.RenameInComments,
cancellationToken: cancellationToken).ConfigureAwait(false);
references.AddRange(renameLocations.Select(
ds => new InlineRenameLocation(ds.Document, ds.TextSpan)));
return new InlineRenameLocationSet(
_renameInfo, _document.Project.Solution,
references.ToImmutableArray());
}
public TextSpan? GetConflictEditSpan(InlineRenameLocation location, string triggerText, string replacementText, CancellationToken cancellationToken)
{
return location.TextSpan;
}
public string GetFinalSymbolName(string replacementText)
{
return replacementText;
}
public TextSpan GetReferenceEditSpan(InlineRenameLocation location, string triggerText, CancellationToken cancellationToken)
{
return location.TextSpan;
}
public bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable<DocumentId> changedDocumentIDs, string replacementText)
{
return true;
}
public bool TryOnBeforeGlobalSymbolRenamed(Workspace workspace, IEnumerable<DocumentId> changedDocumentIDs, string replacementText)
{
return true;
}
private static Glyph FromSymbolKind(SymbolKind kind)
{
var glyph = Glyph.Error;
switch (kind)
{
case SymbolKind.Namespace:
glyph = Glyph.Namespace;
break;
case SymbolKind.NamedType:
glyph = Glyph.ClassPublic;
break;
case SymbolKind.Property:
glyph = Glyph.PropertyPublic;
break;
case SymbolKind.Event:
glyph = Glyph.EventPublic;
break;
}
return glyph;
}
public InlineRenameFileRenameInfo GetFileRenameInfo()
=> InlineRenameFileRenameInfo.NotAllowed;
private class InlineRenameLocationSet : IInlineRenameLocationSet
{
private readonly IXamlRenameInfo _renameInfo;
private readonly Solution _oldSolution;
public InlineRenameLocationSet(IXamlRenameInfo renameInfo, Solution solution, ImmutableArray<InlineRenameLocation> locations)
{
_renameInfo = renameInfo;
_oldSolution = solution;
Locations = locations;
}
public IList<InlineRenameLocation> Locations { get; }
public bool IsReplacementTextValid(string replacementText)
{
return _renameInfo.IsReplacementTextValid(replacementText);
}
public async Task<IInlineRenameReplacementInfo> GetReplacementsAsync(string replacementText, SymbolRenameOptions options, CancellationToken cancellationToken)
{
var newSolution = _oldSolution;
foreach (var group in Locations.GroupBy(l => l.Document))
{
var document = group.Key;
var oldSource = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false);
var newSource = oldSource.WithChanges(group.Select(l => new TextChange(l.TextSpan, replacementText)));
newSolution = newSolution.WithDocumentText(document.Id, newSource);
}
return new InlineRenameReplacementInfo(this, newSolution, replacementText);
}
private class InlineRenameReplacementInfo : IInlineRenameReplacementInfo
{
private readonly InlineRenameLocationSet _inlineRenameLocationSet;
private readonly string _replacementText;
public InlineRenameReplacementInfo(InlineRenameLocationSet inlineRenameLocationSet, Solution newSolution, string replacementText)
{
NewSolution = newSolution;
_inlineRenameLocationSet = inlineRenameLocationSet;
_replacementText = replacementText;
}
public Solution NewSolution { get; }
public IEnumerable<DocumentId> DocumentIds => _inlineRenameLocationSet.Locations.Select(l => l.Document.Id).Distinct();
public bool ReplacementTextValid => _inlineRenameLocationSet.IsReplacementTextValid(_replacementText);
public IEnumerable<InlineRenameReplacement> GetReplacements(DocumentId documentId)
{
yield break;
}
}
}
}
}
}
|