File: Implementation\LanguageServer\Handler\OnTypeRename\OnTypeRenameHandler.cs
Web Access
Project: src\src\VisualStudio\Xaml\Impl\Microsoft.VisualStudio.LanguageServices.Xaml.csproj (Microsoft.VisualStudio.LanguageServices.Xaml)
// 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
            };
        }
    }
}