|
// 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Roslyn.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.Xaml.Features.TypeRename;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Xaml.LanguageServer.Handler
{
[ExportStatelessXamlLspService(typeof(OnTypeRenameHandler)), Shared]
[Method(Methods.TextDocumentLinkedEditingRangeName)]
internal class OnTypeRenameHandler : ILspServiceRequestHandler<LinkedEditingRangeParams, LinkedEditingRanges?>
{
// From https://www.w3.org/TR/xml/#NT-NameStartChar
// Notes:
// \u10000-\uEFFFF isn't included as .NET regular expressions only allow 4 chars after \u.
// The : shouldn't really be used as start character either so included it in the name char pattern.
// We want to allow complete removal and replacement of names so we need to make the start char
// optional in the name char pattern.
// NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
private const string NameStartCharPattern = "A-Z_a-z" +
"\\u00C0-\\u00D6" +
"\\u00D8-\\u00F6" +
"\\u00F8-\\u02FF" +
"\\u0370-\\u037D" +
"\\u037F-\\u1FFF" +
"\\u200C-\\u200D" +
"\\u2070-\\u218F" +
"\\u2C00-\\u2FEF" +
"\\u3001-\\uD7FF" +
"\\uF900-\\uFDCF" +
"\\uFDF0-\\uFFFD";
// NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
private const string NameCharPattern = NameStartCharPattern +
":\\-.0-9" +
"\\u00B7" +
"\\u0300-\\u036F" +
"\\u203F-\\u2040";
// Name ::= NameStartChar (NameChar)*
internal const string NamePattern = $"[{NameStartCharPattern}]?[{NameCharPattern}]*";
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public OnTypeRenameHandler()
{
}
public bool MutatesSolutionState => false;
public bool RequiresLSPSolution => true;
public TextDocumentIdentifier GetTextDocumentIdentifier(LinkedEditingRangeParams request) => request.TextDocument;
public async Task<LinkedEditingRanges?> HandleRequestAsync(LinkedEditingRangeParams request, RequestContext context, CancellationToken cancellationToken)
{
var document = context.Document;
if (document == null)
{
return null;
}
var renameService = document.Project.Services.GetService<IXamlTypeRenameService>();
if (renameService == null)
{
return null;
}
var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false);
var offset = text.Lines.GetPosition(ProtocolConversions.PositionToLinePosition(request.Position));
var result = await renameService.GetTypeRenameAsync(document, offset, cancellationToken).ConfigureAwait(false);
if (result == null)
{
return null;
}
Contract.ThrowIfTrue(result.Ranges.IsDefault);
return new LinkedEditingRanges
{
Ranges = result.Ranges.Select(s => ProtocolConversions.TextSpanToRange(s, text)).ToArray(),
WordPattern = result.WordPattern
};
}
}
}
|