private async Task<Dictionary<string, TextEdit[]>> RemapDocumentEditsAsync(Dictionary<string, TextEdit[]> changes, CancellationToken cancellationToken)
        {
            var remappedChanges = new Dictionary<string, TextEdit[]>();
            foreach (var entry in changes)
            {
                var uri = new Uri(entry.Key);
                var edits = entry.Value;

                if (!CanRemap(uri))
                {
                    // This location doesn't point to a background razor file. No need to remap.
                    remappedChanges[entry.Key] = entry.Value;
                    continue;
                }

                var (_, remappedEdits) = await RemapTextEditsCoreAsync(uri, edits, cancellationToken).ConfigureAwait(false);
                if (remappedEdits == null || remappedEdits.Length == 0)
                {
                    // Nothing to do.
                    continue;
                }

                var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(uri);
                remappedChanges[razorDocumentUri.AbsoluteUri] = remappedEdits;
            }

            return remappedChanges;
        }
        private async Task <(LSPDocumentSnapshot?, TextEdit[])> RemapTextEditsCoreAsync(
            Uri uri,
            TextEdit[] edits,
            TextEditKind textEditKind,
            CancellationToken cancellationToken,
            FormattingOptions?formattingOptions = null)
        {
            var languageKind = RazorLanguageKind.Razor;

            if (RazorLSPConventions.IsVirtualCSharpFile(uri))
            {
                languageKind = RazorLanguageKind.CSharp;
            }
            else if (RazorLSPConventions.IsVirtualHtmlFile(uri))
            {
                languageKind = RazorLanguageKind.Html;
            }
            else
            {
                Debug.Fail("This method should only be called for Razor background files.");
            }

            var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(uri);

            var mapToDocumentEditsParams = new RazorMapToDocumentEditsParams()
            {
                Kind               = languageKind,
                RazorDocumentUri   = razorDocumentUri,
                ProjectedTextEdits = edits,
                TextEditKind       = textEditKind,
                FormattingOptions  = formattingOptions
            };

            if (!_lazyDocumentManager.Value.TryGetDocument(razorDocumentUri, out var documentSnapshot))
            {
                return(null, s_emptyEdits);
            }

            var response = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorMapToDocumentEditsParams, RazorMapToDocumentEditsResponse>(
                documentSnapshot.Snapshot.TextBuffer,
                LanguageServerConstants.RazorMapToDocumentEditsEndpoint,
                RazorLSPConstants.RazorLanguageServerName,
                CheckRazorEditMappingCapability,
                mapToDocumentEditsParams,
                cancellationToken).ConfigureAwait(false);

            var mappingResult = response?.Response;

            if (mappingResult is null ||
                (_lazyDocumentManager.Value.TryGetDocument(razorDocumentUri, out documentSnapshot) &&
                 mappingResult.HostDocumentVersion != documentSnapshot.Version))
            {
                // Couldn't remap the location or the document changed in the meantime. Discard these ranges.
                return(null, s_emptyEdits);
            }

            return(documentSnapshot, mappingResult.TextEdits);
        }
        private async Task <(LSPDocumentSnapshot, TextEdit[])> RemapTextEditsCoreAsync(Uri uri, TextEdit[] edits, CancellationToken cancellationToken)
        {
            var languageKind = RazorLanguageKind.Razor;

            if (RazorLSPConventions.IsRazorCSharpFile(uri))
            {
                languageKind = RazorLanguageKind.CSharp;
            }
            else if (RazorLSPConventions.IsRazorHtmlFile(uri))
            {
                languageKind = RazorLanguageKind.Html;
            }
            else
            {
                Debug.Fail("This method should only be called for Razor background files.");
            }

            var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(uri);

            var rangesToMap   = edits.Select(e => e.Range).ToArray();
            var mappingResult = await MapToDocumentRangesAsync(
                languageKind,
                razorDocumentUri,
                rangesToMap,
                cancellationToken).ConfigureAwait(false);

            if (mappingResult == null ||
                (_lazyDocumentManager.Value.TryGetDocument(razorDocumentUri, out var documentSnapshot) &&
                 mappingResult.HostDocumentVersion != documentSnapshot.Version))
            {
                // Couldn't remap the location or the document changed in the meantime. Discard these ranges.
                return(null, EmptyEdits);
            }

            var remappedEdits = new List <TextEdit>();

            for (var i = 0; i < edits.Length; i++)
            {
                var edit  = edits[i];
                var range = mappingResult.Ranges[i];
                if (range.IsUndefined())
                {
                    // Couldn't remap the range correctly. Discard this range.
                    continue;
                }

                var remappedEdit = new TextEdit()
                {
                    Range   = range,
                    NewText = edit.NewText
                };

                remappedEdits.Add(remappedEdit);
            }

            return(documentSnapshot, remappedEdits.ToArray());
        }
        private async Task <VSInternalReferenceItem[]> RemapReferenceItemsAsync(VSInternalReferenceItem[] result, CancellationToken cancellationToken)
        {
            var remappedLocations = new List <VSInternalReferenceItem>();

            foreach (var referenceItem in result)
            {
                if (referenceItem?.Location is null || referenceItem.Text is null)
                {
                    continue;
                }

                // Temporary fix for codebehind leaking through
                // Revert when https://github.com/dotnet/aspnetcore/issues/22512 is resolved
                referenceItem.DefinitionText = FilterReferenceDisplayText(referenceItem.DefinitionText);
                referenceItem.Text           = FilterReferenceDisplayText(referenceItem.Text);

                // Indicates the reference item is directly available in the code
                referenceItem.Origin = VSInternalItemOrigin.Exact;

                if (!RazorLSPConventions.IsVirtualCSharpFile(referenceItem.Location.Uri) &&
                    !RazorLSPConventions.IsVirtualHtmlFile(referenceItem.Location.Uri))
                {
                    // This location doesn't point to a virtual cs file. No need to remap.
                    remappedLocations.Add(referenceItem);
                    continue;
                }

                var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(referenceItem.Location.Uri);
                var languageKind     = RazorLSPConventions.IsVirtualCSharpFile(referenceItem.Location.Uri) ? RazorLanguageKind.CSharp : RazorLanguageKind.Html;
                var mappingResult    = await _documentMappingProvider.MapToDocumentRangesAsync(
                    languageKind,
                    razorDocumentUri,
                    new[] { referenceItem.Location.Range },
                    cancellationToken).ConfigureAwait(false);

                if (mappingResult == null ||
                    mappingResult.Ranges[0].IsUndefined() ||
                    (_documentManager.TryGetDocument(razorDocumentUri, out var mappedDocumentSnapshot) &&
                     mappingResult.HostDocumentVersion != mappedDocumentSnapshot.Version))
                {
                    // Couldn't remap the location or the document changed in the meantime. Discard this location.
                    continue;
                }

                referenceItem.Location.Uri   = razorDocumentUri;
                referenceItem.DisplayPath    = razorDocumentUri.AbsolutePath;
                referenceItem.Location.Range = mappingResult.Ranges[0];

                remappedLocations.Add(referenceItem);
            }

            return(remappedLocations.ToArray());
        }
Пример #5
0
        private async Task <VSReferenceItem[]> RemapReferenceItemsAsync(VSReferenceItem[] result, CancellationToken cancellationToken)
        {
            var remappedLocations = new List <VSReferenceItem>();

            foreach (var referenceItem in result)
            {
                if (referenceItem?.Location is null || referenceItem.Text is null)
                {
                    continue;
                }

                if (!RazorLSPConventions.IsRazorCSharpFile(referenceItem.Location.Uri))
                {
                    // This location doesn't point to a virtual cs file. No need to remap.
                    remappedLocations.Add(referenceItem);
                    continue;
                }

                var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(referenceItem.Location.Uri);
                var mappingResult    = await _documentMappingProvider.MapToDocumentRangesAsync(
                    RazorLanguageKind.CSharp,
                    razorDocumentUri,
                    new[] { referenceItem.Location.Range },
                    cancellationToken).ConfigureAwait(false);

                if (mappingResult == null ||
                    mappingResult.Ranges[0].IsUndefined() ||
                    (_documentManager.TryGetDocument(razorDocumentUri, out var mappedDocumentSnapshot) &&
                     mappingResult.HostDocumentVersion != mappedDocumentSnapshot.Version))
                {
                    // Couldn't remap the location or the document changed in the meantime. Discard this location.
                    continue;
                }

                referenceItem.Location.Uri   = razorDocumentUri;
                referenceItem.DisplayPath    = razorDocumentUri.AbsolutePath;
                referenceItem.Location.Range = mappingResult.Ranges[0];

                remappedLocations.Add(referenceItem);
            }

            return(remappedLocations.ToArray());
        }
        public async override Task<TextEdit[]> RemapFormattedTextEditsAsync(Uri uri, TextEdit[] edits, FormattingOptions options, CancellationToken cancellationToken)
        {
            if (uri is null)
            {
                throw new ArgumentNullException(nameof(uri));
            }

            if (edits is null)
            {
                throw new ArgumentNullException(nameof(edits));
            }

            if (!RazorLSPConventions.IsRazorCSharpFile(uri) && !RazorLSPConventions.IsRazorHtmlFile(uri))
            {
                // This is not a virtual razor file. No need to remap.
                return edits;
            }

            var (_, remappedEdits) = await RemapTextEditsCoreAsync(uri, edits, cancellationToken, shouldFormat: true, formattingOptions: options).ConfigureAwait(false);
            return remappedEdits;
        }
Пример #7
0
        public async override Task <TextEdit[]> RemapTextEditsAsync(Uri uri, TextEdit[] edits, CancellationToken cancellationToken)
        {
            if (uri is null)
            {
                throw new ArgumentNullException(nameof(uri));
            }

            if (edits is null)
            {
                throw new ArgumentNullException(nameof(edits));
            }

            if (!RazorLSPConventions.IsVirtualCSharpFile(uri) && !RazorLSPConventions.IsVirtualHtmlFile(uri))
            {
                // This is not a virtual razor file. No need to remap.
                return(edits);
            }

            var(_, remappedEdits) = await RemapTextEditsCoreAsync(uri, edits, TextEditKind.Default, cancellationToken).ConfigureAwait(false);

            return(remappedEdits);
        }
        private async Task <TextDocumentEdit[]> RemapVersionedDocumentEditsAsync(TextDocumentEdit[] documentEdits, CancellationToken cancellationToken)
        {
            var remappedDocumentEdits = new List <TextDocumentEdit>();

            foreach (var entry in documentEdits)
            {
                var uri = entry.TextDocument.Uri;
                if (!CanRemap(uri))
                {
                    // This location doesn't point to a background razor file. No need to remap.
                    remappedDocumentEdits.Add(entry);

                    continue;
                }

                var edits = entry.Edits;
                var(documentSnapshot, remappedEdits) = await RemapTextEditsCoreAsync(uri, edits, cancellationToken).ConfigureAwait(false);

                if (remappedEdits == null || remappedEdits.Length == 0)
                {
                    // Nothing to do.
                    continue;
                }

                var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(uri);
                remappedDocumentEdits.Add(new TextDocumentEdit()
                {
                    TextDocument = new VersionedTextDocumentIdentifier()
                    {
                        Uri     = razorDocumentUri,
                        Version = documentSnapshot?.Version
                    },
                    Edits = remappedEdits
                });
            }

            return(remappedDocumentEdits.ToArray());
        }
Пример #9
0
        public async override Task <TextEdit[]> RemapFormattedTextEditsAsync(Uri uri, TextEdit[] edits, FormattingOptions options, bool containsSnippet, CancellationToken cancellationToken)
        {
            if (uri is null)
            {
                throw new ArgumentNullException(nameof(uri));
            }

            if (edits is null)
            {
                throw new ArgumentNullException(nameof(edits));
            }

            if (!RazorLSPConventions.IsVirtualCSharpFile(uri) && !RazorLSPConventions.IsVirtualHtmlFile(uri))
            {
                // This is not a virtual razor file. No need to remap.
                return(edits);
            }

            var textEditKind = containsSnippet ? TextEditKind.Snippet : TextEditKind.FormatOnType;

            var(_, remappedEdits) = await RemapTextEditsCoreAsync(uri, edits, textEditKind, cancellationToken, formattingOptions : options).ConfigureAwait(false);

            return(remappedEdits);
        }
        public async override Task<Location[]> RemapLocationsAsync(Location[] locations, CancellationToken cancellationToken)
        {
            if (locations is null)
            {
                throw new ArgumentNullException(nameof(locations));
            }

            var remappedLocations = new List<Location>();
            foreach (var location in locations)
            {
                var uri = location.Uri;
                RazorLanguageKind languageKind;
                if (RazorLSPConventions.IsRazorCSharpFile(uri))
                {
                    languageKind = RazorLanguageKind.CSharp;
                }
                else if (RazorLSPConventions.IsRazorHtmlFile(uri))
                {
                    languageKind = RazorLanguageKind.Html;
                }
                else
                {
                    // This location doesn't point to a virtual razor file. No need to remap.
                    remappedLocations.Add(location);
                    continue;
                }

                var razorDocumentUri = RazorLSPConventions.GetRazorDocumentUri(uri);

                var mappingResult = await MapToDocumentRangesAsync(
                    languageKind,
                    razorDocumentUri,
                    new[] { location.Range },
                    cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                if (mappingResult == null ||
                    (_lazyDocumentManager.Value.TryGetDocument(razorDocumentUri, out var documentSnapshot) &&
                    mappingResult.HostDocumentVersion != documentSnapshot.Version))
                {
                    // Couldn't remap the location or the document changed in the meantime. Discard these ranges.
                    continue;
                }

                var remappedRange = mappingResult.Ranges[0];
                if (remappedRange.IsUndefined())
                {
                    // Couldn't remap the range correctly. Discard this range.
                    continue;
                }

                var remappedLocation = new Location()
                {
                    Uri = razorDocumentUri,
                    Range = remappedRange,
                };

                remappedLocations.Add(remappedLocation);
            }

            return remappedLocations.ToArray();
        }
 private static bool CanRemap(Uri uri)
 {
     return RazorLSPConventions.IsRazorCSharpFile(uri) || RazorLSPConventions.IsRazorHtmlFile(uri);
 }
Пример #12
0
 private static bool CanRemap(Uri uri)
 {
     return(RazorLSPConventions.IsVirtualCSharpFile(uri) || RazorLSPConventions.IsVirtualHtmlFile(uri));
 }