diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs index 8723c71aae5..4cfa36773c0 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCSharpFormattingBenchmark.cs @@ -11,7 +11,6 @@ using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -123,7 +122,7 @@ public async Task RazorCSharpFormattingAsync() #if DEBUG // For debugging purposes only. - var changedText = DocumentText.WithChanges(edits.Select(e => e.ToTextChange(DocumentText))); + var changedText = DocumentText.WithChanges(edits.Select(DocumentText.GetTextChange)); _ = changedText.ToString(); #endif } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs index 0d3f6ca8dda..8f8a680ae8f 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCodeActionsBenchmark.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer; @@ -78,9 +79,9 @@ public async Task SetupAsync() DocumentSnapshot = await GetDocumentSnapshotAsync(projectFilePath, _filePath, targetPath); DocumentText = await DocumentSnapshot.GetTextAsync(); - RazorCodeActionRange = ToRange(razorCodeActionIndex); - CSharpCodeActionRange = ToRange(csharpCodeActionIndex); - HtmlCodeActionRange = ToRange(htmlCodeActionIndex); + RazorCodeActionRange = DocumentText.GetZeroWidthRange(razorCodeActionIndex); + CSharpCodeActionRange = DocumentText.GetZeroWidthRange(csharpCodeActionIndex); + HtmlCodeActionRange = DocumentText.GetZeroWidthRange(htmlCodeActionIndex); var documentContext = new VersionedDocumentContext(DocumentUri, DocumentSnapshot, projectContext: null, 1); @@ -89,16 +90,6 @@ public async Task SetupAsync() codeDocument.SetCodeGenerationOptions(RazorCodeGenerationOptions.Create(c => c.RootNamespace = "Root.Namespace")); RazorRequestContext = new RazorRequestContext(documentContext, RazorLanguageServerHost.GetRequiredService(), "lsp/method", uri: null); - - Range ToRange(int index) - { - DocumentText.GetLineAndOffset(index, out var line, out var offset); - return new Range - { - Start = new Position(line, offset), - End = new Position(line, offset) - }; - } } private string GetFileContents(FileTypes fileType) diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs index 16a6b55da14..f9baad11704 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorCompletionBenchmark.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -49,7 +48,7 @@ public async Task SetupAsync() var configurationService = new DefaultRazorConfigurationService(clientConnection, loggerFactory); var optionsMonitor = new RazorLSPOptionsMonitor(configurationService, RazorLSPOptions.Default); - CompletionEndpoint = new RazorCompletionEndpoint(completionListProvider, telemetryReporter: null, optionsMonitor, loggerFactory); + CompletionEndpoint = new RazorCompletionEndpoint(completionListProvider, telemetryReporter: null, optionsMonitor); var clientCapabilities = new VSInternalClientCapabilities { @@ -78,16 +77,10 @@ public async Task SetupAsync() DocumentSnapshot = await GetDocumentSnapshotAsync(projectFilePath, _filePath, targetPath); DocumentText = await DocumentSnapshot.GetTextAsync(); - RazorPosition = ToPosition(razorCodeActionIndex); + RazorPosition = DocumentText.GetPosition(razorCodeActionIndex); var documentContext = new VersionedDocumentContext(DocumentUri, DocumentSnapshot, projectContext: null, 1); RazorRequestContext = new RazorRequestContext(documentContext, RazorLanguageServerHost.GetRequiredService(), "lsp/method", uri: null); - - Position ToPosition(int index) - { - DocumentText.GetLineAndOffset(index, out var line, out var offset); - return new Position(line, offset); - } } private static string GetFileContents() diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs index 88a1e8dc183..7cb21677aa5 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDiagnosticsBenchmark.cs @@ -22,6 +22,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer; @@ -206,10 +207,10 @@ public Task SendRequestAsync(string method, TPara } } - private Range InRange { get; set; } = new Range { Start = new Position(85, 8), End = new Position(85, 16) }; - private Range OutRange { get; set; } = new Range { Start = new Position(6, 8), End = new Position(6, 16) }; + private Range InRange { get; set; } = VsLspFactory.CreateSingleLineRange(line: 85, character: 8, length: 8); + private Range OutRange { get; set; } = VsLspFactory.CreateSingleLineRange(line: 6, character: 8, length: 8); - private Diagnostic[] GetDiagnostics(int N) => Enumerable.Range(1, N).Select(_ => new Diagnostic() + private Diagnostic[] GetDiagnostics(int n) => Enumerable.Range(1, n).Select(_ => new Diagnostic() { Range = InRange, Code = "CS0103", diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs index e322a6c9f2e..d489b9ec124 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorDocumentMappingBenchmark.cs @@ -147,7 +147,7 @@ private bool TryMapToHostDocumentPosition(IRazorGeneratedDocument generatedDocum // Found the generated span that contains the generated absolute index hostDocumentIndex = mapping.OriginalSpan.AbsoluteIndex + distanceIntoGeneratedSpan; - hostDocumentPosition = codeDocument.Source.Text.Lines.GetLinePosition(hostDocumentIndex); + hostDocumentPosition = codeDocument.Source.Text.GetLinePosition(hostDocumentIndex); return true; } } diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs index 92fbd456b08..6f053edeadc 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensBenchmark.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Immutable; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; @@ -21,6 +20,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer; @@ -66,19 +66,9 @@ public async Task InitializeRazorSemanticAsync() DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version); var text = await DocumentContext.GetSourceTextAsync(CancellationToken.None).ConfigureAwait(false); - Range = new Range - { - Start = new Position - { - Line = 0, - Character = 0 - }, - End = new Position - { - Line = text.Lines.Count - 1, - Character = text.Lines.Last().Span.Length - 1 - } - }; + Range = VsLspFactory.CreateRange( + start: (0, 0), + end: (text.Lines.Count - 1, text.Lines[^1].Span.Length - 1)); } [Benchmark(Description = "Razor Semantic Tokens Range Handling")] diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs index e0541b54efe..6bd676543de 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensRangeEndpointBenchmark.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Immutable; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; @@ -23,6 +22,7 @@ using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer; @@ -62,8 +62,6 @@ public async Task InitializeRazorSemanticAsync() { EnsureServicesInitialized(); - var loggerFactory = RazorLanguageServerHost.GetRequiredService(); - var projectRoot = Path.Combine(RepoRoot, "src", "Razor", "test", "testapps", "ComponentApp"); ProjectFilePath = Path.Combine(projectRoot, "ComponentApp.csproj"); PagesDirectory = Path.Combine(projectRoot, "Components", "Pages"); @@ -81,11 +79,9 @@ public async Task InitializeRazorSemanticAsync() SemanticTokensRangeEndpoint = new SemanticTokensRangeEndpoint(RazorSemanticTokenService, razorSemanticTokensLegendService, razorOptionsMonitor, telemetryReporter: null); var text = await DocumentContext.GetSourceTextAsync(CancellationToken.None).ConfigureAwait(false); - Range = new Range - { - Start = new Position { Line = 0, Character = 0 }, - End = new Position { Line = text.Lines.Count - 1, Character = text.Lines.Last().Span.Length - 1 } - }; + Range = VsLspFactory.CreateRange( + start: (0, 0), + end: (text.Lines.Count - 1, text.Lines[^1].Span.Length - 1)); var documentVersion = 1; VersionCache.TrackDocumentVersion(DocumentSnapshot, documentVersion); diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs index e2146d85e47..4063270b669 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/LanguageServer/RazorSemanticTokensScrollingBenchmark.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.LanguageServer.Protocol; using static Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer.RazorSemanticTokensBenchmark; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.LanguageServer; @@ -54,19 +55,9 @@ public async Task InitializeRazorSemanticAsync() DocumentContext = new VersionedDocumentContext(documentUri, documentSnapshot, projectContext: null, version: 1); var text = await DocumentSnapshot.GetTextAsync().ConfigureAwait(false); - Range = new Range - { - Start = new Position - { - Line = 0, - Character = 0 - }, - End = new Position - { - Line = text.Lines.Count - 1, - Character = 0 - } - }; + Range = VsLspFactory.CreateRange( + start: (0, 0), + end: (text.Lines.Count - 1, 0)); } private const int WindowSize = 10; diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.csproj b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.csproj index 3b9bc7150e2..1010350dd29 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.csproj +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks.csproj @@ -11,10 +11,6 @@ false - - - - diff --git a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs index 2c9ecda9bf9..9e98822d88d 100644 --- a/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs +++ b/src/Razor/benchmarks/Microsoft.AspNetCore.Razor.Microbenchmarks/Serialization/CompletionListSerializationBenchmark.cs @@ -5,11 +5,11 @@ using System.Text.Json; using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer; using Microsoft.AspNetCore.Razor.LanguageServer.Completion; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.CodeAnalysis.Razor.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.Microbenchmarks.Serialization; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs index 836378c8640..88574c846ba 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AbstractRazorDelegatingEndpoint.cs @@ -113,7 +113,7 @@ protected virtual Task HandleDelegatedResponseAsync(TResponse delegat return default; } - var positionInfo = await DocumentPositionInfoStrategy.TryGetPositionInfoAsync(_documentMappingService, documentContext, request.Position, Logger, cancellationToken).ConfigureAwait(false); + var positionInfo = await DocumentPositionInfoStrategy.TryGetPositionInfoAsync(_documentMappingService, documentContext, request.Position, cancellationToken).ConfigureAwait(false); if (positionInfo is null) { return default; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs index a69469ab185..e216c899d0d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/AutoClosingTagOnAutoInsertProvider.cs @@ -8,13 +8,12 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert; -internal sealed class AutoClosingTagOnAutoInsertProvider : IOnAutoInsertProvider +internal sealed class AutoClosingTagOnAutoInsertProvider(RazorLSPOptionsMonitor optionsMonitor) : IOnAutoInsertProvider { // From http://dev.w3.org/html5/spec/Overview.html#elements-0 private static readonly ImmutableHashSet s_voidElements = ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, @@ -36,26 +35,10 @@ internal sealed class AutoClosingTagOnAutoInsertProvider : IOnAutoInsertProvider "track", "wbr" ); - private static readonly ImmutableHashSet s_voidElementsCaseSensitive = s_voidElements.WithComparer(StringComparer.Ordinal); - - private readonly RazorLSPOptionsMonitor _optionsMonitor; - private readonly ILogger _logger; - public AutoClosingTagOnAutoInsertProvider(RazorLSPOptionsMonitor optionsMonitor, ILoggerFactory loggerFactory) - { - if (optionsMonitor is null) - { - throw new ArgumentNullException(nameof(optionsMonitor)); - } - - if (loggerFactory is null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } + private static readonly ImmutableHashSet s_voidElementsCaseSensitive = s_voidElements.WithComparer(StringComparer.Ordinal); - _optionsMonitor = optionsMonitor; - _logger = loggerFactory.GetOrCreateLogger(); - } + private readonly RazorLSPOptionsMonitor _optionsMonitor = optionsMonitor; public string TriggerCharacter => ">"; @@ -68,7 +51,7 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N return false; } - if (!position.TryGetAbsoluteIndex(context.SourceText, _logger, out var afterCloseAngleIndex)) + if (!context.SourceText.TryGetAbsoluteIndex(position, out var afterCloseAngleIndex)) { format = default; edit = default; @@ -85,11 +68,7 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N if (autoClosingBehavior == AutoClosingBehavior.EndTag) { format = InsertTextFormat.Snippet; - edit = new TextEdit() - { - NewText = $"$0", - Range = new Range { Start = position, End = position }, - }; + edit = VsLspFactory.CreateTextEdit(position, $"$0"); return true; } @@ -100,16 +79,7 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N // Need to replace the `>` with ' />$0' or '/>$0' depending on if there's prefixed whitespace. var insertionText = char.IsWhiteSpace(context.SourceText[afterCloseAngleIndex - 2]) ? "/" : " /"; - var insertionPosition = new Position(position.Line, position.Character - 1); - edit = new TextEdit() - { - NewText = insertionText, - Range = new Range - { - Start = insertionPosition, - End = insertionPosition - } - }; + edit = VsLspFactory.CreateTextEdit(position.Line, position.Character - 1, insertionText); return true; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/CloseTextTagOnAutoInsertProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/CloseTextTagOnAutoInsertProvider.cs index 81207b73be5..8ce976721ee 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/CloseTextTagOnAutoInsertProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/CloseTextTagOnAutoInsertProvider.cs @@ -8,32 +8,14 @@ using Microsoft.AspNetCore.Razor.Language.Legacy; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert; -internal sealed class CloseTextTagOnAutoInsertProvider : IOnAutoInsertProvider +internal sealed class CloseTextTagOnAutoInsertProvider(RazorLSPOptionsMonitor optionsMonitor) : IOnAutoInsertProvider { - private readonly RazorLSPOptionsMonitor _optionsMonitor; - private readonly ILogger _logger; - - public CloseTextTagOnAutoInsertProvider(RazorLSPOptionsMonitor optionsMonitor, ILoggerFactory loggerFactory) - { - if (optionsMonitor is null) - { - throw new ArgumentNullException(nameof(optionsMonitor)); - } - - if (loggerFactory is null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - _optionsMonitor = optionsMonitor; - _logger = loggerFactory.GetOrCreateLogger(); - } + private readonly RazorLSPOptionsMonitor _optionsMonitor = optionsMonitor; public string TriggerCharacter => ">"; @@ -47,7 +29,7 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N return false; } - if (!IsAtTextTag(context, position, _logger)) + if (!IsAtTextTag(context, position)) { format = default; edit = default; @@ -56,20 +38,16 @@ public bool TryResolveInsertion(Position position, FormattingContext context, [N // This is a text tag. format = InsertTextFormat.Snippet; - edit = new TextEdit() - { - NewText = $"$0", - Range = new Range { Start = position, End = position }, - }; + edit = VsLspFactory.CreateTextEdit(position, $"$0"); return true; } - private static bool IsAtTextTag(FormattingContext context, Position position, ILogger logger) + private static bool IsAtTextTag(FormattingContext context, Position position) { var syntaxTree = context.CodeDocument.GetSyntaxTree(); - if (!position.TryGetAbsoluteIndex(context.SourceText, logger, out var absoluteIndex)) + if (!context.SourceText.TryGetAbsoluteIndex(position, out var absoluteIndex)) { return false; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs index 70454c11b6a..3169a1d7648 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionStrategy.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -21,9 +20,9 @@ internal class PreferHtmlInAttributeValuesDocumentPositionInfoStrategy : IDocume { public static IDocumentPositionInfoStrategy Instance { get; } = new PreferHtmlInAttributeValuesDocumentPositionInfoStrategy(); - public async Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, ILogger logger, CancellationToken cancellationToken) + public async Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, CancellationToken cancellationToken) { - var defaultDocumentPositionInfo = await DefaultDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync(documentMappingService, documentContext, position, logger, cancellationToken).ConfigureAwait(false); + var defaultDocumentPositionInfo = await DefaultDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync(documentMappingService, documentContext, position, cancellationToken).ConfigureAwait(false); if (defaultDocumentPositionInfo is null) { return null; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/TypeAccessibilityCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/TypeAccessibilityCodeActionProvider.cs index 4e4263e54c9..0cbd6d6f4a6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/TypeAccessibilityCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CSharp/TypeAccessibilityCodeActionProvider.cs @@ -16,7 +16,7 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Threading; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; @@ -81,13 +81,15 @@ private static ImmutableArray ProcessCodeActionsVSCod { // Corner case handling for diagnostics which (momentarily) linger after // @code block is cleared out - if (diagnostic.Range.End.Line > context.SourceText.Lines.Count || - diagnostic.Range.End.Character > context.SourceText.Lines[diagnostic.Range.End.Line].End) + var range = diagnostic.Range; + var end = range.End; + if (end.Line > context.SourceText.Lines.Count || + end.Character > context.SourceText.Lines[end.Line].End) { continue; } - var diagnosticSpan = diagnostic.Range.ToTextSpan(context.SourceText); + var diagnosticSpan = context.SourceText.GetTextSpan(range); // Based on how we compute `Range.AsTextSpan` it's possible to have a span // which goes beyond the end of the source text. Something likely changed @@ -259,11 +261,7 @@ private static RazorVSInternalCodeAction CreateFQNCodeAction( { var codeDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier() { Uri = context.Request.TextDocument.Uri }; - var fqnTextEdit = new TextEdit() - { - NewText = fullyQualifiedName, - Range = fqnDiagnostic.Range - }; + var fqnTextEdit = VsLspFactory.CreateTextEdit(fqnDiagnostic.Range, fullyQualifiedName); var fqnWorkspaceEditDocumentChange = new TextDocumentEdit() { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index 1acf449023b..124f3fc5935 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -22,6 +22,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using StreamJsonRpc; @@ -151,13 +152,13 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V // context. // // Note: VS Code doesn't provide a `SelectionRange`. - var vsCodeActionContext = (VSInternalCodeActionContext)request.Context; + var vsCodeActionContext = request.Context; if (vsCodeActionContext.SelectionRange != null) { request.Range = vsCodeActionContext.SelectionRange; } - if (!request.Range.Start.TryGetSourceLocation(sourceText, _logger, out var location)) + if (!sourceText.TryGetSourceLocation(request.Range.Start, out var location)) { return null; } @@ -166,7 +167,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V request, documentSnapshot, codeDocument, - location.Value, + location, sourceText, _languageServerFeatureOptions.SupportsFileManipulation, _supportsCodeActionResolve); @@ -339,12 +340,12 @@ private static ImmutableHashSet GetAllAvailableCodeActionNames() .GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) .Where(property => property.PropertyType == typeof(string)) .Select(property => property.GetValue(null) as string) - .WithoutNull(); + .WhereNotNull(); var codeFixProviderNames = typeof(RazorPredefinedCodeFixProviderNames) .GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public) .Where(property => property.PropertyType == typeof(string)) .Select(property => property.GetValue(null) as string) - .WithoutNull(); + .WhereNotNull(); availableCodeActionNames.AddRange(refactoringProviderNames); availableCodeActionNames.AddRange(codeFixProviderNames); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs index 919bb61de8c..5f7f6d007e0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Html/DefaultHtmlCodeActionProvider.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/AddUsingsCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/AddUsingsCodeActionResolver.cs index 51dbd90ebbe..5923d2ed861 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/AddUsingsCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/AddUsingsCodeActionResolver.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Text.Json; @@ -18,7 +17,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; @@ -123,9 +122,8 @@ private static TextDocumentEdit GenerateSingleUsingEditsInterpolated( if (string.CompareOrdinal(newUsingNamespace, usingDirectiveNamespace) < 0) { - var usingDirectiveLineIndex = codeDocument.Source.Text.Lines.GetLinePosition(usingDirective.Node.Span.Start).Line; - var head = new Position(usingDirectiveLineIndex, 0); - var edit = new TextEdit() { Range = new Range { Start = head, End = head }, NewText = newText }; + var usingDirectiveLineIndex = codeDocument.Source.Text.GetLinePosition(usingDirective.Node.Span.Start).Line; + var edit = VsLspFactory.CreateTextEdit(line: usingDirectiveLineIndex, character: 0, newText); edits.Add(edit); break; } @@ -136,8 +134,7 @@ private static TextDocumentEdit GenerateSingleUsingEditsInterpolated( { var endIndex = existingUsingDirectives[^1].Node.Span.End; var lineIndex = GetLineIndexOrEnd(codeDocument, endIndex - 1) + 1; - var head = new Position(lineIndex, 0); - var edit = new TextEdit() { Range = new Range { Start = head, End = head }, NewText = newText }; + var edit = VsLspFactory.CreateTextEdit(line: lineIndex, character: 0, newText); edits.Add(edit); } @@ -153,33 +150,25 @@ private static TextDocumentEdit GenerateSingleUsingEditsAtTop( OptionalVersionedTextDocumentIdentifier codeDocumentIdentifier, string newUsingNamespace) { - var head = new Position(0, 0); + var insertPosition = (0, 0); // If we don't have usings, insert after the last namespace or page directive, which ever comes later var syntaxTreeRoot = codeDocument.GetSyntaxTree().Root; var lastNamespaceOrPageDirective = syntaxTreeRoot .DescendantNodes() - .Where(n => IsNamespaceOrPageDirective(n)) - .LastOrDefault(); + .LastOrDefault(IsNamespaceOrPageDirective); + if (lastNamespaceOrPageDirective != null) { var lineIndex = GetLineIndexOrEnd(codeDocument, lastNamespaceOrPageDirective.Span.End - 1) + 1; - head = new Position(lineIndex, 0); + insertPosition = (lineIndex, 0); } // Insert all usings at the given point - var range = new Range { Start = head, End = head }; return new TextDocumentEdit { TextDocument = codeDocumentIdentifier, - Edits = - [ - new TextEdit() - { - NewText = string.Concat($"@using {newUsingNamespace}{Environment.NewLine}"), - Range = range, - } - ] + Edits = [VsLspFactory.CreateTextEdit(insertPosition, newText: $"@using {newUsingNamespace}{Environment.NewLine}")] }; } @@ -187,7 +176,7 @@ private static int GetLineIndexOrEnd(RazorCodeDocument codeDocument, int endInde { if (endIndex < codeDocument.Source.Text.Length) { - return codeDocument.Source.Text.Lines.GetLinePosition(endIndex).Line; + return codeDocument.Source.Text.GetLinePosition(endIndex).Line; } else { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CodeBlockService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CodeBlockService.cs index 7b20beeda4b..9cda5df9204 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CodeBlockService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CodeBlockService.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -42,7 +41,8 @@ public static TextEdit[] CreateFormattedTextEdit(RazorCodeDocument code, string { var csharpCodeBlock = code.GetSyntaxTree().Root.DescendantNodes() .Select(RazorSyntaxFacts.TryGetCSharpCodeFromCodeBlock) - .FirstOrDefault(n => n is not null); + .FirstOrDefault(static n => n is not null); + if (csharpCodeBlock is null || !csharpCodeBlock.Children.TryGetOpenBraceNode(out var openBrace) || !csharpCodeBlock.Children.TryGetCloseBraceNode(out var closeBrace)) @@ -60,25 +60,10 @@ public static TextEdit[] CreateFormattedTextEdit(RazorCodeDocument code, string codeBlockStartText = $"{Environment.NewLine}{codeBlockStartText}"; } - var eofPosition = new Position(lastCharacterLocation.LineNumber, insertCharacterIndex); - var eofRange = new Range { Start = eofPosition, End = eofPosition }; - var start = new TextEdit() - { - NewText = codeBlockStartText, - Range = eofRange - }; - - var method = new TextEdit() - { - NewText = indentedMethod, - Range = eofRange - }; - - var end = new TextEdit() - { - NewText = Environment.NewLine + "}", - Range = eofRange - }; + var eofRange = VsLspFactory.CreateZeroWidthRange(lastCharacterLocation.LineNumber, insertCharacterIndex); + var start = VsLspFactory.CreateTextEdit(eofRange, codeBlockStartText); + var method = VsLspFactory.CreateTextEdit(eofRange, indentedMethod); + var end = VsLspFactory.CreateTextEdit(eofRange, Environment.NewLine + "}"); return [start, method, end]; } @@ -88,7 +73,7 @@ public static TextEdit[] CreateFormattedTextEdit(RazorCodeDocument code, string var openBraceLocation = openBrace.GetSourceLocation(code.Source); var closeBraceLocation = closeBrace.GetSourceLocation(code.Source); var previousLineAbsoluteIndex = closeBraceLocation.AbsoluteIndex - closeBraceLocation.CharacterIndex - 1; - var previousLine = code.Source.Text.Lines.GetLinePosition(previousLineAbsoluteIndex); + var previousLine = code.Source.Text.GetLinePosition(previousLineAbsoluteIndex); var insertLineLocation = openBraceLocation.LineIndex == closeBraceLocation.LineIndex || !IsLineEmpty(code.Source.Text.Lines[previousLine.Line]) @@ -107,15 +92,8 @@ public static TextEdit[] CreateFormattedTextEdit(RazorCodeDocument code, string var insertCharacter = openBraceLocation.LineIndex == closeBraceLocation.LineIndex ? closeBraceLocation.CharacterIndex : 0; - var insertPosition = new Position(insertLineLocation.LineIndex, insertCharacter); - - var edit = new TextEdit() - { - Range = new Range { Start = insertPosition, End = insertPosition }, - NewText = formattedGeneratedMethod - }; - return [edit]; + return [VsLspFactory.CreateTextEdit(insertLineLocation.LineIndex, insertCharacter, formattedGeneratedMethod)]; } private static string FormatMethodInCodeBlock( diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs index 29fabbac9ae..1404d1910a9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ComponentAccessibilityCodeActionProvider.cs @@ -16,7 +16,6 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis.Razor; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Editor.Razor; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -277,23 +276,14 @@ private static WorkspaceEdit CreateRenameTagEdit(RazorCodeActionContext context, using var textEdits = new PooledArrayBuilder(); var codeDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier() { Uri = context.Request.TextDocument.Uri }; - var startTagTextEdit = new TextEdit - { - Range = startTag.Name.GetRange(context.CodeDocument.Source), - NewText = newTagName, - }; + var startTagTextEdit = VsLspFactory.CreateTextEdit(startTag.Name.GetRange(context.CodeDocument.Source), newTagName); textEdits.Add(startTagTextEdit); var endTag = (startTag.Parent as MarkupElementSyntax)?.EndTag; if (endTag != null) { - var endTagTextEdit = new TextEdit - { - Range = endTag.Name.GetRange(context.CodeDocument.Source), - NewText = newTagName, - }; - + var endTagTextEdit = VsLspFactory.CreateTextEdit(endTag.Name.GetRange(context.CodeDocument.Source), newTagName); textEdits.Add(endTagTextEdit); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs index aa08bd57a5d..75d538382ab 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/CreateComponentCodeActionResolver.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Text.Json; using System.Threading; @@ -78,8 +77,7 @@ private static void TryAddNamespaceDirective(RazorCodeDocument codeDocument, Uri var namespaceDirective = syntaxTree.Root.DescendantNodes() .Where(n => n.Kind == SyntaxKind.RazorDirective) .Cast() - .Where(n => n.DirectiveDescriptor == NamespaceDirective.Directive) - .FirstOrDefault(); + .FirstOrDefault(static n => n.DirectiveDescriptor == NamespaceDirective.Directive); if (namespaceDirective != null) { @@ -87,14 +85,7 @@ private static void TryAddNamespaceDirective(RazorCodeDocument codeDocument, Uri documentChanges.Add(new TextDocumentEdit { TextDocument = documentIdentifier, - Edits = - [ - new TextEdit() - { - NewText = namespaceDirective.GetContent(), - Range = new Range{ Start = new Position(0, 0), End = new Position(0, 0) }, - } - ] + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), namespaceDirective.GetContent())] }); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionProvider.cs index 546b5f71d32..297ac7c24c1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionProvider.cs @@ -17,7 +17,6 @@ using Microsoft.AspNetCore.Razor.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs index 4fc7b9fd4eb..74a832a0f2b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/ExtractToCodeBehindCodeActionResolver.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; @@ -84,13 +85,7 @@ internal sealed class ExtractToCodeBehindCodeActionResolver( var codeBlockContent = text.GetSubTextString(new CodeAnalysis.Text.TextSpan(actionParams.ExtractStart, actionParams.ExtractEnd - actionParams.ExtractStart)).Trim(); var codeBehindContent = await GenerateCodeBehindClassAsync(documentContext.Project, codeBehindUri, className, actionParams.Namespace, codeBlockContent, codeDocument, cancellationToken).ConfigureAwait(false); - var start = codeDocument.Source.Text.Lines.GetLinePosition(actionParams.RemoveStart); - var end = codeDocument.Source.Text.Lines.GetLinePosition(actionParams.RemoveEnd); - var removeRange = new Range - { - Start = new Position(start.Line, start.Character), - End = new Position(end.Line, end.Character) - }; + var removeRange = codeDocument.Source.Text.GetRange(actionParams.RemoveStart, actionParams.RemoveEnd); var codeDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = actionParams.Uri }; var codeBehindDocumentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = codeBehindUri }; @@ -101,30 +96,12 @@ internal sealed class ExtractToCodeBehindCodeActionResolver( new TextDocumentEdit { TextDocument = codeDocumentIdentifier, - Edits = - [ - new TextEdit - { - NewText = string.Empty, - Range = removeRange, - } - ], + Edits = [VsLspFactory.CreateTextEdit(removeRange, string.Empty)] }, new TextDocumentEdit { TextDocument = codeBehindDocumentIdentifier, - Edits = - [ - new TextEdit - { - NewText = codeBehindContent, - Range = new Range - { - Start = new Position(0, 0), - End = new Position(0, 0) - }, - } - ], + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), codeBehindContent)] } }; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs index ea478048fed..f79fe80a516 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/Razor/GenerateMethodCodeActionResolver.cs @@ -112,12 +112,10 @@ razorClassName is null || classLocationLineSpan.StartLinePosition.Character, content); - var insertPosition = new Position(classLocationLineSpan.EndLinePosition.Line, 0); - var edit = new TextEdit() - { - Range = new Range { Start = insertPosition, End = insertPosition }, - NewText = $"{formattedMethod}{Environment.NewLine}" - }; + var edit = VsLspFactory.CreateTextEdit( + line: classLocationLineSpan.EndLinePosition.Line, + character: 0, + $"{formattedMethod}{Environment.NewLine}"); var delegatedParams = new DelegatedSimplifyMethodParams( new TextDocumentIdentifierAndVersion(new TextDocumentIdentifier() { Uri = codeBehindUri }, 1), @@ -163,12 +161,10 @@ private async Task GenerateMethodInCodeBlockAsync( // just get the simplified text that comes back from Roslyn. var classLocationLineSpan = @class.GetLocation().GetLineSpan(); - var insertPosition = new Position(classLocationLineSpan.EndLinePosition.Line, 0); - var tempTextEdit = new TextEdit() - { - NewText = editToSendToRoslyn.NewText, - Range = new Range() { Start = insertPosition, End = insertPosition } - }; + var tempTextEdit = VsLspFactory.CreateTextEdit( + line: classLocationLineSpan.EndLinePosition.Line, + character: 0, + editToSendToRoslyn.NewText); var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.Identifier, RequiresVirtualDocument: true, tempTextEdit); var result = await _clientConnection.SendRequestAsync( @@ -196,11 +192,7 @@ private async Task GenerateMethodInCodeBlockAsync( .Replace(FormattingUtilities.InitialIndent, string.Empty) .Replace(FormattingUtilities.Indent, string.Empty); - var remappedEdit = new TextEdit() - { - NewText = unformattedMethodSignature, - Range = remappedRange - }; + var remappedEdit = VsLspFactory.CreateTextEdit(remappedRange, unformattedMethodSignature); var delegatedParams = new DelegatedSimplifyMethodParams(documentContext.Identifier, RequiresVirtualDocument: true, remappedEdit); var result = await _clientConnection.SendRequestAsync( diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs index dd131ef2021..e830fee0ff0 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DelegatedCompletionListProvider.cs @@ -214,19 +214,11 @@ private static VSInternalCompletionContext RewriteContext(VSInternalCompletionCo // Edit the CSharp projected document to contain a '.'. This allows C# completion to provide valid // completion items for moments when a user has typed a '.' that's typically interpreted as Html. - var addProvisionalDot = new TextEdit() - { - Range = new Range() - { - Start = previousPosition, - End = previousPosition, - }, - NewText = ".", - }; + var addProvisionalDot = VsLspFactory.CreateTextEdit(previousPosition, "."); var provisionalPositionInfo = new DocumentPositionInfo( RazorLanguageKind.CSharp, - new Position( + VsLspFactory.CreatePosition( previousPosition.Line, previousPosition.Character + 1), previousCharacterPositionInfo.HostDocumentIndex + 1); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DesignTimeHelperResponseRewriter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DesignTimeHelperResponseRewriter.cs index cdf564e7a88..675b2d27148 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DesignTimeHelperResponseRewriter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/DesignTimeHelperResponseRewriter.cs @@ -5,10 +5,10 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using RazorSyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/TextEditResponseRewriter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/TextEditResponseRewriter.cs index dc7f86e9e88..fff2e226c9b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/TextEditResponseRewriter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/Delegation/TextEditResponseRewriter.cs @@ -1,13 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion.Delegation; @@ -30,8 +27,7 @@ public override async Task RewriteAsync( var sourceText = await hostDocumentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - sourceText.GetLineAndOffset(hostDocumentIndex, out var lineNumber, out var characterOffset); - var hostDocumentPosition = new Position(lineNumber, characterOffset); + var hostDocumentPosition = sourceText.GetPosition(hostDocumentIndex); completionList = TranslateTextEdits(hostDocumentPosition, delegatedParameters.ProjectedPosition, completionList); if (completionList.ItemDefaults?.EditRange is { } editRange) @@ -91,26 +87,18 @@ private static Range TranslateRange(Position hostDocumentPosition, Position proj { var offset = projectedPosition.Character - hostDocumentPosition.Character; - var editStartPosition = textEditRange.Start; - var translatedStartPosition = TranslatePosition(offset, hostDocumentPosition, editStartPosition); - var editEndPosition = textEditRange.End; - var translatedEndPosition = TranslatePosition(offset, hostDocumentPosition, editEndPosition); - var translatedRange = new Range() - { - Start = translatedStartPosition, - End = translatedEndPosition, - }; + var translatedStartPosition = TranslatePosition(offset, hostDocumentPosition, textEditRange.Start); + var translatedEndPosition = TranslatePosition(offset, hostDocumentPosition, textEditRange.End); - return translatedRange; - } + return VsLspFactory.CreateRange(translatedStartPosition, translatedEndPosition); - private static Position TranslatePosition(int offset, Position hostDocumentPosition, Position editPosition) - { - var translatedCharacter = editPosition.Character - offset; + static Position TranslatePosition(int offset, Position hostDocumentPosition, Position editPosition) + { + var translatedCharacter = editPosition.Character - offset; - // Note: If this completion handler ever expands to deal with multi-line TextEdits, this logic will likely need to change since - // it assumes we're only dealing with single-line TextEdits. - var translatedPosition = new Position(hostDocumentPosition.Line, translatedCharacter); - return translatedPosition; + // Note: If this completion handler ever expands to deal with multi-line TextEdits, this logic will likely need to change since + // it assumes we're only dealing with single-line TextEdits. + return VsLspFactory.CreatePosition(hostDocumentPosition.Line, translatedCharacter); + } } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/DirectiveAttributeTransitionCompletionItemProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/DirectiveAttributeTransitionCompletionItemProvider.cs index 2159101bc6e..d3a0831a7bb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/DirectiveAttributeTransitionCompletionItemProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/DirectiveAttributeTransitionCompletionItemProvider.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Razor.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs index 1147d96cfd9..fea284d3d97 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs @@ -8,8 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.Telemetry; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; @@ -18,14 +17,12 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; internal class RazorCompletionEndpoint( CompletionListProvider completionListProvider, ITelemetryReporter? telemetryReporter, - RazorLSPOptionsMonitor optionsMonitor, - ILoggerFactory loggerFactory) + RazorLSPOptionsMonitor optionsMonitor) : IRazorRequestHandler, ICapabilitiesProvider { private readonly CompletionListProvider _completionListProvider = completionListProvider; private readonly ITelemetryReporter? _telemetryReporter = telemetryReporter; private readonly RazorLSPOptionsMonitor _optionsMonitor = optionsMonitor; - private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); private VSInternalClientCapabilities? _clientCapabilities; @@ -57,7 +54,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(CompletionParams request } var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (!request.Position.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex)) + if (!sourceText.TryGetAbsoluteIndex(request.Position, out var hostDocumentIndex)) { return null; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionListProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionListProvider.cs index dd60824f058..e73f38dcad8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionListProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionListProvider.cs @@ -9,11 +9,11 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Completion; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Completion; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs index 90033fe958a..f28856851d3 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorBreakpointSpanEndpoint.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Debugging; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -55,8 +54,7 @@ public Uri GetTextDocumentIdentifier(RazorBreakpointSpanParams request) var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - var linePosition = new LinePosition(request.Position.Line, request.Position.Character); - var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); + var hostDocumentIndex = sourceText.GetPosition(request.Position); if (codeDocument.IsUnsupported()) { @@ -91,15 +89,7 @@ public Uri GetTextDocumentIdentifier(RazorBreakpointSpanParams request) } var csharpText = codeDocument.GetCSharpSourceText(); - - csharpText.GetLineAndOffset(csharpBreakpointSpan.Start, out var startLineIndex, out var startCharacterIndex); - csharpText.GetLineAndOffset(csharpBreakpointSpan.End, out var endLineIndex, out var endCharacterIndex); - - var projectedRange = new Range() - { - Start = new Position(startLineIndex, startCharacterIndex), - End = new Position(endLineIndex, endCharacterIndex), - }; + var projectedRange = csharpText.GetRange(csharpBreakpointSpan); // Now map that new C# location back to the host document // Razor files generate code in a "loosely" debuggable way. For instance if you were to do the following in a razor or cshtml file: diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs index 0ec3fcb4371..cf6700e9a68 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Debugging/RazorProximityExpressionsEndpoint.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol.Debugging; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; +using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; @@ -59,8 +60,7 @@ public Uri GetTextDocumentIdentifier(RazorProximityExpressionsParams request) var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - var linePosition = new LinePosition(request.Position.Line, request.Position.Character); - var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); + var hostDocumentIndex = sourceText.GetPosition(request.Position); if (codeDocument.IsUnsupported()) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs index c421b4e8e97..a9ebe134264 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultDocumentPositionInfoStrategy.cs @@ -4,9 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer; @@ -15,10 +14,14 @@ internal class DefaultDocumentPositionInfoStrategy : IDocumentPositionInfoStrate { public static IDocumentPositionInfoStrategy Instance { get; } = new DefaultDocumentPositionInfoStrategy(); - public async Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, ILogger logger, CancellationToken cancellationToken) + public async Task TryGetPositionInfoAsync( + IRazorDocumentMappingService documentMappingService, + DocumentContext documentContext, + Position position, + CancellationToken cancellationToken) { var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (!position.TryGetAbsoluteIndex(sourceText, logger, out var absoluteIndex)) + if (!sourceText.TryGetAbsoluteIndex(position, out var absoluteIndex)) { return null; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs index 99c24a7e8d2..09de8ae52f2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DefaultRazorComponentSearchEngine.cs @@ -2,16 +2,10 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.IO; -using System.Linq; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.Intermediate; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.LanguageServer; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs index dff4ceeecaa..3a6aad8e6f6 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Definition/DefinitionEndpoint.cs @@ -22,6 +22,7 @@ Microsoft.VisualStudio.LanguageServer.Protocol.VSInternalLocation, Microsoft.VisualStudio.LanguageServer.Protocol.VSInternalLocation[], Microsoft.VisualStudio.LanguageServer.Protocol.DocumentLink[]>; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; using SyntaxKind = Microsoft.AspNetCore.Razor.Language.SyntaxKind; namespace Microsoft.AspNetCore.Razor.LanguageServer.Definition; @@ -263,7 +264,7 @@ private async Task GetNavigateRangeAsync(IDocumentSnapshot documentSnapsh // If we were trying to navigate to a property, and we couldn't find it, we can at least take // them to the file for the component. If the property was defined in a partial class they can // at least then press F7 to go there. - return new Range { Start = new Position(0, 0), End = new Position(0, 0) }; + return VsLspFactory.DefaultRange; } internal static async Task TryGetPropertyRangeAsync(RazorCodeDocument codeDocument, string propertyName, IRazorDocumentMappingService documentMappingService, ILogger logger, CancellationToken cancellationToken) @@ -301,7 +302,7 @@ private async Task GetNavigateRangeAsync(IDocumentSnapshot documentSnapsh return null; } - var range = property.Identifier.Span.ToRange(csharpText); + var range = csharpText.GetRange(property.Identifier.Span); if (documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), range, out var originalRange)) { return originalRange; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticConverter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticConverter.cs index cdce48937a8..1ee9556ff92 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticConverter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorDiagnosticConverter.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; @@ -78,26 +79,8 @@ internal static DiagnosticSeverity ConvertSeverity(RazorDiagnosticSeverity sever } var spanStartIndex = Math.Min(sourceSpan.AbsoluteIndex, sourceText.Length); - var startPosition = sourceText.Lines.GetLinePosition(spanStartIndex); - var start = new Position() - { - Line = startPosition.Line, - Character = startPosition.Character, - }; - var spanEndIndex = Math.Min(sourceSpan.AbsoluteIndex + sourceSpan.Length, sourceText.Length); - var endPosition = sourceText.Lines.GetLinePosition(spanEndIndex); - var end = new Position() - { - Line = endPosition.Line, - Character = endPosition.Character, - }; - var range = new Range() - { - Start = start, - End = end, - }; - return range; + return sourceText.GetRange(spanStartIndex, spanEndIndex); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs index 43f2b5d9af5..7831e806f0b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/RazorTranslateDiagnosticsService.cs @@ -15,14 +15,11 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Diagnostic = Microsoft.VisualStudio.LanguageServer.Protocol.Diagnostic; using DiagnosticSeverity = Microsoft.VisualStudio.LanguageServer.Protocol.DiagnosticSeverity; -using Position = Microsoft.VisualStudio.LanguageServer.Protocol.Position; -using RazorDiagnosticFactory = Microsoft.AspNetCore.Razor.Language.RazorDiagnosticFactory; -using SourceText = Microsoft.CodeAnalysis.Text.SourceText; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; using SyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; @@ -71,7 +68,7 @@ internal async Task TranslateAsync( var filteredDiagnostics = diagnosticKind == RazorLanguageKind.CSharp ? FilterCSharpDiagnostics(diagnostics, codeDocument, sourceText) - : FilterHTMLDiagnostics(diagnostics, codeDocument, sourceText, _logger); + : FilterHTMLDiagnostics(diagnostics, codeDocument, sourceText); if (filteredDiagnostics.Length == 0) { _logger.LogDebug($"No diagnostics remaining after filtering."); @@ -99,8 +96,7 @@ private Diagnostic[] FilterCSharpDiagnostics(Diagnostic[] unmappedDiagnostics, R private static Diagnostic[] FilterHTMLDiagnostics( Diagnostic[] unmappedDiagnostics, RazorCodeDocument codeDocument, - SourceText sourceText, - ILogger logger) + SourceText sourceText) { var syntaxTree = codeDocument.GetSyntaxTree(); @@ -109,9 +105,9 @@ private static Diagnostic[] FilterHTMLDiagnostics( var filteredDiagnostics = unmappedDiagnostics .Where(d => !InCSharpLiteral(d, sourceText, syntaxTree) && - !InAttributeContainingCSharp(d, sourceText, syntaxTree, processedAttributes, logger) && - !AppliesToTagHelperTagName(d, sourceText, syntaxTree, logger) && - !ShouldFilterHtmlDiagnosticBasedOnErrorCode(d, sourceText, syntaxTree, logger)) + !InAttributeContainingCSharp(d, sourceText, syntaxTree, processedAttributes) && + !AppliesToTagHelperTagName(d, sourceText, syntaxTree) && + !ShouldFilterHtmlDiagnosticBasedOnErrorCode(d, sourceText, syntaxTree)) .ToArray(); return filteredDiagnostics; @@ -165,7 +161,7 @@ private static bool InCSharpLiteral( return false; } - var owner = syntaxTree.Root.FindNode(d.Range.ToTextSpan(sourceText), getInnermostNodeForTie: true); + var owner = syntaxTree.Root.FindNode(sourceText.GetTextSpan(d.Range), getInnermostNodeForTie: true); if (IsCsharpKind(owner)) { return true; @@ -187,11 +183,7 @@ or SyntaxKind.CSharpStatementLiteral or SyntaxKind.CSharpEphemeralTextLiteral; } - private static bool AppliesToTagHelperTagName( - Diagnostic diagnostic, - SourceText sourceText, - RazorSyntaxTree syntaxTree, - ILogger logger) + private static bool AppliesToTagHelperTagName(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { // Goal of this method is to filter diagnostics that touch TagHelper tag names. Reason being is TagHelpers can output anything. Meaning // If you have a TagHelper like: @@ -207,9 +199,9 @@ private static bool AppliesToTagHelperTagName( return false; } - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.End, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.End); - var startOrEndTag = owner?.FirstAncestorOrSelf(n => n is MarkupTagHelperStartTagSyntax || n is MarkupTagHelperEndTagSyntax); + var startOrEndTag = owner?.FirstAncestorOrSelf(static n => n is MarkupTagHelperStartTagSyntax || n is MarkupTagHelperEndTagSyntax); if (startOrEndTag is null) { return false; @@ -228,7 +220,7 @@ private static bool AppliesToTagHelperTagName( return true; } - private static bool ShouldFilterHtmlDiagnosticBasedOnErrorCode(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) + private static bool ShouldFilterHtmlDiagnosticBasedOnErrorCode(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { if (!diagnostic.Code.HasValue) { @@ -239,36 +231,36 @@ private static bool ShouldFilterHtmlDiagnosticBasedOnErrorCode(Diagnostic diagno return str switch { - CSSErrorCodes.MissingOpeningBrace => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree, logger), - CSSErrorCodes.MissingSelectorAfterCombinator => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree, logger), - CSSErrorCodes.MissingSelectorBeforeCombinatorCode => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree, logger), - HtmlErrorCodes.UnexpectedEndTagErrorCode => IsHtmlWithBangAndMatchingTags(diagnostic, sourceText, syntaxTree, logger), - HtmlErrorCodes.InvalidNestingErrorCode => IsAnyFilteredInvalidNestingError(diagnostic, sourceText, syntaxTree, logger), + CSSErrorCodes.MissingOpeningBrace => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree), + CSSErrorCodes.MissingSelectorAfterCombinator => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree), + CSSErrorCodes.MissingSelectorBeforeCombinatorCode => IsCSharpInStyleBlock(diagnostic, sourceText, syntaxTree), + HtmlErrorCodes.UnexpectedEndTagErrorCode => IsHtmlWithBangAndMatchingTags(diagnostic, sourceText, syntaxTree), + HtmlErrorCodes.InvalidNestingErrorCode => IsAnyFilteredInvalidNestingError(diagnostic, sourceText, syntaxTree), HtmlErrorCodes.MissingEndTagErrorCode => FileKinds.IsComponent(syntaxTree.Options.FileKind), // Redundant with RZ9980 in Components - HtmlErrorCodes.TooFewElementsErrorCode => IsAnyFilteredTooFewElementsError(diagnostic, sourceText, syntaxTree, logger), + HtmlErrorCodes.TooFewElementsErrorCode => IsAnyFilteredTooFewElementsError(diagnostic, sourceText, syntaxTree), _ => false, }; - static bool IsCSharpInStyleBlock(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) + static bool IsCSharpInStyleBlock(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { // C# in a style block causes diagnostics because the HTML background document replaces C# with "~" - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start); if (owner is null) { return false; } - var element = owner.FirstAncestorOrSelf(n => n.StartTag?.Name.Content == "style"); + var element = owner.FirstAncestorOrSelf(static n => n.StartTag?.Name.Content == "style"); var csharp = owner.FirstAncestorOrSelf(); - return element?.Body.Any(c => c is CSharpCodeBlockSyntax) ?? false || csharp is not null; + return element?.Body.Any(static c => c is CSharpCodeBlockSyntax) ?? false || csharp is not null; } // Ideally this would be solved instead by not emitting the "!" at the HTML backing file, // but we don't currently have a system to accomplish that - static bool IsAnyFilteredTooFewElementsError(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) + static bool IsAnyFilteredTooFewElementsError(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start); if (owner is null) { return false; @@ -287,7 +279,7 @@ static bool IsAnyFilteredTooFewElementsError(Diagnostic diagnostic, SourceText s var bodyElement = element .ChildNodes() - .SingleOrDefault(c => c is MarkupElementSyntax tag && tag.StartTag?.Name.Content == "body") as MarkupElementSyntax; + .SingleOrDefault(static c => c is MarkupElementSyntax tag && tag.StartTag?.Name.Content == "body") as MarkupElementSyntax; return bodyElement is not null && bodyElement.StartTag?.Bang is not null; @@ -295,9 +287,9 @@ static bool IsAnyFilteredTooFewElementsError(Diagnostic diagnostic, SourceText s // Ideally this would be solved instead by not emitting the "!" at the HTML backing file, // but we don't currently have a system to accomplish that - static bool IsHtmlWithBangAndMatchingTags(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) + static bool IsHtmlWithBangAndMatchingTags(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start); if (owner is null) { return false; @@ -319,13 +311,13 @@ static bool IsHtmlWithBangAndMatchingTags(Diagnostic diagnostic, SourceText sour return haveBang && namesEquivalent; } - static bool IsAnyFilteredInvalidNestingError(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) - => IsInvalidNestingWarningWithinComponent(diagnostic, sourceText, syntaxTree, logger) || - IsInvalidNestingFromBody(diagnostic, sourceText, syntaxTree, logger); + static bool IsAnyFilteredInvalidNestingError(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) + => IsInvalidNestingWarningWithinComponent(diagnostic, sourceText, syntaxTree) || + IsInvalidNestingFromBody(diagnostic, sourceText, syntaxTree); - static bool IsInvalidNestingWarningWithinComponent(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) + static bool IsInvalidNestingWarningWithinComponent(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start); if (owner is null) { return false; @@ -338,15 +330,15 @@ static bool IsInvalidNestingWarningWithinComponent(Diagnostic diagnostic, Source // Ideally this would be solved instead by not emitting the "!" at the HTML backing file, // but we don't currently have a system to accomplish that - static bool IsInvalidNestingFromBody(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, ILogger logger) + static bool IsInvalidNestingFromBody(Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree) { - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.Start); if (owner is null) { return false; } - var body = owner.FirstAncestorOrSelf(n => n.StartTag?.Name.Content.Equals("body", StringComparison.Ordinal) == true); + var body = owner.FirstAncestorOrSelf(static n => n.StartTag?.Name.Content.Equals("body", StringComparison.Ordinal) == true); if (ReferenceEquals(body, owner)) { @@ -366,8 +358,7 @@ private static bool InAttributeContainingCSharp( Diagnostic diagnostic, SourceText sourceText, RazorSyntaxTree syntaxTree, - Dictionary processedAttributes, - ILogger logger) + Dictionary processedAttributes) { // Examine the _end_ of the diagnostic to see if we're at the // start of an (im/ex)plicit expression. Looking at the start @@ -377,13 +368,13 @@ private static bool InAttributeContainingCSharp( return false; } - var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.End, logger); + var owner = syntaxTree.FindInnermostNode(sourceText, diagnostic.Range.End); if (owner is null) { return false; } - var markupAttributeNode = owner.FirstAncestorOrSelf(n => + var markupAttributeNode = owner.FirstAncestorOrSelf(static n => n is MarkupAttributeBlockSyntax || n is MarkupTagHelperAttributeSyntax || n is MarkupMiscAttributeContentSyntax); @@ -405,7 +396,7 @@ static bool CheckIfAttributeContainsNonMarkupNodes(RazorSyntaxNode attributeNode { // Only allow markup, generic & (non-razor comment) token nodes var containsNonMarkupNodes = attributeNode.DescendantNodes() - .Any(n => !(n is MarkupBlockSyntax || + .Any(static n => !(n is MarkupBlockSyntax || n is MarkupSyntaxNode || n is GenericBlockSyntax || (n is SyntaxNode sn && sn.IsToken && sn.Kind != SyntaxKind.RazorCommentTransition))); @@ -483,7 +474,7 @@ private bool TryGetOriginalDiagnosticRange(Diagnostic diagnostic, RazorCodeDocum // For `Error` Severity diagnostics we still show the diagnostics to // the user, however we set the range to an undefined range to ensure // clicking on the diagnostic doesn't cause errors. - originalRange = RangeExtensions.UndefinedRange; + originalRange = VsLspFactory.UndefinedRange; } return true; @@ -503,7 +494,7 @@ private bool TryRemapRudeEditRange(Range diagnosticRange, RazorCodeDocument code // semi-intelligent way. var syntaxTree = codeDocument.GetSyntaxTree(); - var span = diagnosticRange.ToTextSpan(codeDocument.GetSourceText()); + var span = codeDocument.Source.Text.GetTextSpan(diagnosticRange); var owner = syntaxTree.Root.FindNode(span, getInnermostNodeForTie: true); switch (owner?.Kind) @@ -531,9 +522,10 @@ private bool TryRemapRudeEditRange(Range diagnosticRange, RazorCodeDocument code var startLine = sourceText.Lines[startLineIndex]; // Look for the first non-whitespace character so we're not squiggling random whitespace at the start of the diagnostic - var firstNonWhitespaceCharacterOffset = sourceText.GetFirstNonWhitespaceOffset(startLine.Span, out _); - var diagnosticStartCharacter = firstNonWhitespaceCharacterOffset ?? 0; - var startLinePosition = new Position(startLineIndex, diagnosticStartCharacter); + var diagnosticStartCharacter = sourceText.TryGetFirstNonWhitespaceOffset(startLine.Span, out var firstNonWhitespaceOffset) + ? firstNonWhitespaceOffset + : 0; + var startLinePosition = (startLineIndex, diagnosticStartCharacter); var endLineIndex = diagnosticRange.End.Line; if (endLineIndex >= sourceText.Lines.Count) @@ -546,16 +538,13 @@ private bool TryRemapRudeEditRange(Range diagnosticRange, RazorCodeDocument code var endLine = sourceText.Lines[endLineIndex]; // Look for the last non-whitespace character so we're not squiggling random whitespace at the end of the diagnostic - var lastNonWhitespaceCharacterOffset = sourceText.GetLastNonWhitespaceOffset(endLine.Span, out _); - var diagnosticEndCharacter = lastNonWhitespaceCharacterOffset ?? 0; + var diagnosticEndCharacter = sourceText.TryGetLastNonWhitespaceOffset(endLine.Span, out var lastNonWhitespaceOffset) + ? lastNonWhitespaceOffset + : 0; var diagnosticEndWhitespaceOffset = diagnosticEndCharacter + 1; - var endLinePosition = new Position(endLineIndex, diagnosticEndWhitespaceOffset); + var endLinePosition = (endLineIndex, diagnosticEndWhitespaceOffset); - remappedRange = new Range - { - Start = startLinePosition, - End = endLinePosition - }; + remappedRange = VsLspFactory.CreateRange(startLinePosition, endLinePosition); return true; } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs index 21b230bec19..5854d01677e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentHighlighting/DocumentHighlightEndpoint.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Threading; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs index 2a66dc32eab..e2134c10ed2 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/AbstractTextDocumentPresentationEndpointBase.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -18,6 +17,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentPresentation; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.DocumentPresentation; @@ -36,10 +36,10 @@ protected AbstractTextDocumentPresentationEndpointBase( IFilePathService filePathService, ILogger logger) { - _razorDocumentMappingService = razorDocumentMappingService ?? throw new ArgumentNullException(nameof(razorDocumentMappingService)); - _clientConnection = clientConnection ?? throw new ArgumentNullException(nameof(clientConnection)); - _filePathService = filePathService ?? throw new ArgumentNullException(nameof(filePathService)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _razorDocumentMappingService = razorDocumentMappingService; + _clientConnection = clientConnection; + _filePathService = filePathService; + _logger = logger; } public abstract string EndpointName { get; } @@ -74,7 +74,7 @@ protected AbstractTextDocumentPresentationEndpointBase( } var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (request.Range.Start.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex) != true) + if (sourceText.TryGetAbsoluteIndex(request.Range.Start, out var hostDocumentIndex) != true) { return null; } @@ -238,11 +238,7 @@ private TextEdit[] MapTextEdits(bool mapRanges, RazorCodeDocument codeDocument, return []; } - var newEdit = new TextEdit() - { - NewText = edit.NewText, - Range = newRange - }; + var newEdit = VsLspFactory.CreateTextEdit(newRange, edit.NewText); mappedEdits.Add(newEdit); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs index 360e956b882..72cf2558498 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentPresentation/TextDocumentUriPresentationEndpoint.cs @@ -2,12 +2,9 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; -using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.DocumentPresentation; using Microsoft.CodeAnalysis.Razor.Logging; @@ -79,14 +76,7 @@ protected override IRazorPresentationParams CreateRazorRequestParameters(UriPres { Uri = request.TextDocument.Uri }, - Edits = - [ - new TextEdit - { - NewText = componentTagText, - Range = request.Range - } - ] + Edits = [VsLspFactory.CreateTextEdit(request.Range, componentTagText)] } } }; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSynchronization/DocumentDidChangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSynchronization/DocumentDidChangeEndpoint.cs index aa34b3b43b2..afd1da50b3c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSynchronization/DocumentDidChangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/DocumentSynchronization/DocumentDidChangeEndpoint.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.LanguageServer.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -70,17 +69,14 @@ internal SourceText ApplyContentChanges(IEnumerable GetFormattingEditsAsync(FormattingContext context, Range projectedRange, CancellationToken cancellationToken) { var csharpSourceText = context.CodeDocument.GetCSharpSourceText(); - var spanToFormat = projectedRange.ToTextSpan(csharpSourceText); + var spanToFormat = csharpSourceText.GetTextSpan(projectedRange); var root = await context.CSharpWorkspaceDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); Assumes.NotNull(root); var changes = RazorCSharpFormattingInteractionService.GetFormattedTextChanges(context.CSharpWorkspace.Services, root, spanToFormat, context.Options.GetIndentationOptions(), cancellationToken); - var edits = changes.Select(c => c.ToTextEdit(csharpSourceText)).ToArray(); + var edits = changes.Select(csharpSourceText.GetTextEdit).ToArray(); return edits; } @@ -265,8 +264,8 @@ static bool ShouldIgnoreLineCompletelyBecauseOfAncestors(SyntaxToken token, Sour static bool SpansMultipleLines(SyntaxNode node, SourceText text) { - var range = node.Span.ToRange(text); - return range.Start.Line != range.End.Line; + var range = text.GetRange(node.Span); + return range.SpansMultipleLines(); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs index 81abf67078e..ae44807e53d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPass.cs @@ -8,14 +8,12 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; -using TextSpan = Microsoft.CodeAnalysis.Text.TextSpan; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -43,7 +41,7 @@ public async override Task ExecuteAsync(FormattingContext cont var changedContext = context; if (result.Edits.Length > 0) { - var changes = result.Edits.Select(e => e.ToTextChange(originalText)).ToArray(); + var changes = result.Edits.Select(originalText.GetTextChange).ToArray(); changedText = changedText.WithChanges(changes); changedContext = await context.WithTextAsync(changedText).ConfigureAwait(false); } @@ -54,7 +52,7 @@ public async override Task ExecuteAsync(FormattingContext cont var csharpEdits = await FormatCSharpAsync(changedContext, cancellationToken).ConfigureAwait(false); if (csharpEdits.Length > 0) { - var csharpChanges = csharpEdits.Select(c => c.ToTextChange(changedText)); + var csharpChanges = csharpEdits.Select(changedText.GetTextChange); changedText = changedText.WithChanges(csharpChanges); changedContext = await changedContext.WithTextAsync(changedText).ConfigureAwait(false); @@ -75,7 +73,7 @@ public async override Task ExecuteAsync(FormattingContext cont _logger.LogTestOnly($"Generated C#:\r\n{context.CSharpSourceText}"); var finalChanges = changedText.GetTextChanges(originalText); - var finalEdits = finalChanges.Select(f => f.ToTextEdit(originalText)).ToArray(); + var finalEdits = finalChanges.Select(originalText.GetTextEdit).ToArray(); return new FormattingResult(finalEdits); } @@ -95,7 +93,7 @@ private async Task> FormatCSharpAsync(FormattingContext } // These should already be remapped. - var range = span.ToRange(sourceText); + var range = sourceText.GetRange(span); var edits = await CSharpFormatter.FormatAsync(context, range, cancellationToken).ConfigureAwait(false); csharpEdits.AddRange(edits.Where(e => range.Contains(e.Range))); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs index 7c5dc36bf31..ab97332f801 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpFormattingPassBase.cs @@ -12,9 +12,9 @@ using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; -using TextSpan = Microsoft.CodeAnalysis.Text.TextSpan; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -38,7 +38,7 @@ protected async Task> AdjustIndentationAsync(FormattingContext // 2. The indentation due to Razor and HTML constructs var text = context.SourceText; - range ??= TextSpan.FromBounds(0, text.Length).ToRange(text); + range ??= text.GetRange(TextSpan.FromBounds(0, text.Length)); // To help with figuring out the correct indentation, first we will need the indentation // that the C# formatter wants to apply in the following locations, @@ -521,8 +521,8 @@ bool IsSingleLineExplicitExpression() // `|@{ foo }` - true // if (owner is { Parent.Parent.Parent: CSharpExplicitExpressionSyntax explicitExpression } && - explicitExpression.Span.ToRange(context.SourceText) is { } exprRange && - exprRange.Start.Line == exprRange.End.Line) + context.SourceText.GetRange(explicitExpression.Span) is { } exprRange && + exprRange.IsSingleLine()) { return true; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs index f900e4ae41b..1c60b4fa464 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/CSharpOnTypeFormattingPass.cs @@ -18,9 +18,9 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; using SyntaxNode = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxNode; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -72,7 +72,7 @@ public async override Task ExecuteAsync(FormattingContext cont return result; } - textEdits = formattingChanges.Select(change => change.ToTextEdit(csharpText)).ToArray(); + textEdits = formattingChanges.Select(csharpText.GetTextEdit).ToArray(); _logger.LogInformation($"Received {textEdits.Length} results from C#."); } @@ -108,17 +108,17 @@ public async override Task ExecuteAsync(FormattingContext cont } // Find the lines that were affected by these edits. - var originalText = codeDocument.GetSourceText(); + var originalText = codeDocument.Source.Text; _logger.LogTestOnly($"Original text:\r\n{originalText}"); - var changes = filteredEdits.Select(e => e.ToTextChange(originalText)); + var changes = filteredEdits.Select(originalText.GetTextChange); // Apply the format on type edits sent over by the client. var formattedText = ApplyChangesAndTrackChange(originalText, changes, out _, out var spanAfterFormatting); _logger.LogTestOnly($"After C# changes:\r\n{formattedText}"); var changedContext = await context.WithTextAsync(formattedText).ConfigureAwait(false); - var rangeAfterFormatting = spanAfterFormatting.ToRange(formattedText); + var rangeAfterFormatting = formattedText.GetRange(spanAfterFormatting); cancellationToken.ThrowIfCancellationRequested(); @@ -179,15 +179,15 @@ public async override Task ExecuteAsync(FormattingContext cont start = firstPosition; } - var end = new Position(rangeAfterFormatting.End.Line + lineDelta, 0); + var end = VsLspFactory.CreatePosition(rangeAfterFormatting.End.Line + lineDelta, 0); if (lastPosition is not null && lastPosition.CompareTo(start) < 0) { end = lastPosition; } - var rangeToAdjust = new Range { Start = start, End = end }; + var rangeToAdjust = VsLspFactory.CreateRange(start, end); - Debug.Assert(rangeToAdjust.End.IsValid(cleanedText), "Invalid range. This is unexpected."); + Debug.Assert(cleanedText.IsValidPosition(rangeToAdjust.End), "Invalid range. This is unexpected."); var indentationChanges = await AdjustIndentationAsync(changedContext, cancellationToken, rangeToAdjust).ConfigureAwait(false); if (indentationChanges.Count > 0) @@ -200,7 +200,7 @@ public async override Task ExecuteAsync(FormattingContext cont // Now that we have made all the necessary changes to the document. Let's diff the original vs final version and return the diff. var finalChanges = cleanedText.GetTextChanges(originalText); - var finalEdits = finalChanges.Select(f => f.ToTextEdit(originalText)).ToArray(); + var finalEdits = finalChanges.Select(originalText.GetTextEdit).ToArray(); finalEdits = await AddUsingStatementEditsIfNecessaryAsync(context, codeDocument, csharpText, textEdits, originalTextWithChanges, finalEdits, cancellationToken).ConfigureAwait(false); @@ -238,7 +238,7 @@ private static TextEdit[] FilterCSharpTextEdits(FormattingContext context, TextE { var filteredEdits = edits.Where(e => { - var span = e.Range.ToTextSpan(context.SourceText); + var span = context.SourceText.GetTextSpan(e.Range); return ShouldFormat(context, span, allowImplicitStatements: false); }).ToArray(); @@ -257,7 +257,7 @@ private static int LineDelta(SourceText text, IEnumerable changes, o { var newLineCount = change.NewText is null ? 0 : change.NewText.Split('\n').Length - 1; - var range = change.Span.ToRange(text); + var range = text.GetRange(change.Span); Debug.Assert(range.Start.Line <= range.End.Line, "Invalid range."); // For convenience, since we're already iterating through things, we also find the extremes @@ -283,14 +283,14 @@ private static int LineDelta(SourceText text, IEnumerable changes, o private static List CleanupDocument(FormattingContext context, Range? range = null) { var text = context.SourceText; - range ??= TextSpan.FromBounds(0, text.Length).ToRange(text); + range ??= text.GetRange(TextSpan.FromBounds(0, text.Length)); var csharpDocument = context.CodeDocument.GetCSharpDocument(); var changes = new List(); foreach (var mapping in csharpDocument.SourceMappings) { var mappingSpan = new TextSpan(mapping.OriginalSpan.AbsoluteIndex, mapping.OriginalSpan.Length); - var mappingRange = mappingSpan.ToRange(text); + var mappingRange = text.GetRange(mappingSpan); if (!range.LineOverlapsWith(mappingRange)) { // We don't care about this range. It didn't change. @@ -326,7 +326,7 @@ private static void CleanupSourceMappingStart(FormattingContext context, Range s // var text = context.SourceText; - var sourceMappingSpan = sourceMappingRange.ToTextSpan(text); + var sourceMappingSpan = text.GetTextSpan(sourceMappingRange); if (!ShouldFormat(context, sourceMappingSpan, allowImplicitStatements: false, out var owner)) { // We don't want to run cleanup on this range. @@ -374,8 +374,7 @@ private static void CleanupSourceMappingStart(FormattingContext context, Range s // } // We want to return the length of the range marked by |...| // - var whitespaceLength = text.GetFirstNonWhitespaceOffset(sourceMappingSpan, out var newLineCount); - if (whitespaceLength is null) + if (!text.TryGetFirstNonWhitespaceOffset(sourceMappingSpan, out var whitespaceLength, out var newLineCount)) { // There was no content after the start of this mapping. Meaning it already is clean. // E.g, @@ -386,7 +385,7 @@ private static void CleanupSourceMappingStart(FormattingContext context, Range s return; } - var spanToReplace = new TextSpan(sourceMappingSpan.Start, whitespaceLength.Value); + var spanToReplace = new TextSpan(sourceMappingSpan.Start, whitespaceLength); if (!context.TryGetIndentationLevel(spanToReplace.End, out var contentIndentLevel)) { // Can't find the correct indentation for this content. Leave it alone. @@ -454,7 +453,7 @@ private static void CleanupSourceMappingEnd(FormattingContext context, Range sou // var text = context.SourceText; - var sourceMappingSpan = sourceMappingRange.ToTextSpan(text); + var sourceMappingSpan = text.GetTextSpan(sourceMappingRange); var mappingEndLineIndex = sourceMappingRange.End.Line; var indentations = context.GetIndentations(); @@ -538,18 +537,17 @@ private static void CleanupSourceMappingEnd(FormattingContext context, Range sou private static bool IsOnSingleLine(SyntaxNode node, SourceText text) { - text.GetLineAndOffset(node.Span.Start, out var startLine, out _); - text.GetLineAndOffset(node.Span.End, out var endLine, out _); + var linePositionSpan = text.GetLinePositionSpan(node.Span); - return startLine == endLine; + return linePositionSpan.Start.Line == linePositionSpan.End.Line; } private static TextEdit[] NormalizeTextEdits(SourceText originalText, TextEdit[] edits, out SourceText originalTextWithChanges) { - var changes = edits.Select(e => e.ToTextChange(originalText)); + var changes = edits.Select(originalText.GetTextChange); originalTextWithChanges = originalText.WithChanges(changes); var cleanChanges = SourceTextDiffer.GetMinimalTextChanges(originalText, originalTextWithChanges, DiffKind.Char); - var cleanEdits = cleanChanges.Select(c => c.ToTextEdit(originalText)).ToArray(); + var cleanEdits = cleanChanges.Select(originalText.GetTextEdit).ToArray(); return cleanEdits; } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs index 2af85bc6b5c..71389874fcc 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/DocumentOnTypeFormattingEndpoint.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -90,7 +90,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DocumentOnTypeFormatting } var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (!request.Position.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex)) + if (!sourceText.TryGetAbsoluteIndex(request.Position, out var hostDocumentIndex)) { return null; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs index c3a89ac1f2e..ec990b20f27 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContentValidationPass.cs @@ -1,16 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -40,7 +38,7 @@ public override Task ExecuteAsync(FormattingContext context, F var text = context.SourceText; var edits = result.Edits; - var changes = edits.Select(e => e.ToTextChange(text)); + var changes = edits.Select(text.GetTextChange); var changedText = text.WithChanges(changes); if (!text.NonWhitespaceContentEquals(changedText)) @@ -56,10 +54,9 @@ public override Task ExecuteAsync(FormattingContext context, F { _logger.LogWarning($"{SR.FormatEdit_at_adds(edit.Range.ToDisplayString(), edit.NewText)}"); } - else if (text.GetSubText(edit.Range.ToTextSpan(text)) is { } subText && - subText.GetFirstNonWhitespaceOffset(span: null, out _) is not null) + else if (text.TryGetFirstNonWhitespaceOffset(text.GetTextSpan(edit.Range), out _)) { - _logger.LogWarning($"{SR.FormatEdit_at_deletes(edit.Range.ToDisplayString(), subText.ToString())}"); + _logger.LogWarning($"{SR.FormatEdit_at_deletes(edit.Range.ToDisplayString(), text.ToString(text.GetTextSpan(edit.Range)))}"); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContext.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContext.cs index f2920f86b01..9e1c13b6e92 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContext.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingContext.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -51,7 +50,7 @@ private FormattingContext(IAdhocWorkspaceFactory workspaceFactory, Uri uri, IDoc public int HostDocumentIndex { get; } public char TriggerCharacter { get; } - public SourceText SourceText => CodeDocument.GetSourceText(); + public SourceText SourceText => CodeDocument.Source.Text; public SourceText CSharpSourceText => CodeDocument.GetCSharpSourceText(); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs index 74822f1f5d9..ed7d5014b05 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/FormattingDiagnosticValidationPass.cs @@ -8,11 +8,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -44,7 +42,7 @@ public async override Task ExecuteAsync(FormattingContext cont var text = context.SourceText; var edits = result.Edits; - var changes = edits.Select(e => e.ToTextChange(text)); + var changes = edits.Select(text.GetTextChange); var changedText = text.WithChanges(changes); var changedContext = await context.WithTextAsync(changedText).ConfigureAwait(false); var changedDiagnostics = changedContext.CodeDocument.GetSyntaxTree().Diagnostics; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs index ee2bea56b52..288afdeacac 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormatter.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Razor.TextDifferencing; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Formatting; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -69,10 +68,9 @@ public async Task FormatOnTypeAsync( return Array.Empty(); } - context.SourceText.GetLineAndOffset(context.HostDocumentIndex, out var line, out var col); var @params = new RazorDocumentOnTypeFormattingParams() { - Position = new Position(line, col), + Position = context.SourceText.GetPosition(context.HostDocumentIndex), Character = context.TriggerCharacter.ToString(), TextDocument = new TextDocumentIdentifier { Uri = context.Uri }, Options = context.Options, @@ -100,12 +98,12 @@ public static TextEdit[] FixHtmlTestEdits(SourceText htmlSourceText, TextEdit[] return edits; // First we apply the edits that the Html language server wanted, to the Html document - var textChanges = edits.Select(e => e.ToTextChange(htmlSourceText)); + var textChanges = edits.Select(htmlSourceText.GetTextChange); var changedText = htmlSourceText.WithChanges(textChanges); // Now we use our minimal text differ algorithm to get the bare minimum of edits var minimalChanges = SourceTextDiffer.GetMinimalTextChanges(htmlSourceText, changedText, DiffKind.Char); - var minimalEdits = minimalChanges.Select(f => f.ToTextEdit(htmlSourceText)).ToArray(); + var minimalEdits = minimalChanges.Select(htmlSourceText.GetTextEdit).ToArray(); return minimalEdits; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs index d3ea1aee609..988494d9858 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/HtmlFormattingPass.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -59,7 +58,7 @@ public async override Task ExecuteAsync(FormattingContext cont if (htmlEdits.Length > 0) { - var changes = htmlEdits.Select(e => e.ToTextChange(originalText)); + var changes = htmlEdits.Select(originalText.GetTextChange); changedText = originalText.WithChanges(changes); // Create a new formatting context for the changed razor document. changedContext = await context.WithTextAsync(changedText).ConfigureAwait(false); @@ -81,7 +80,7 @@ public async override Task ExecuteAsync(FormattingContext cont } var finalChanges = changedText.GetTextChanges(originalText); - var finalEdits = finalChanges.Select(f => f.ToTextEdit(originalText)).ToArray(); + var finalEdits = finalChanges.Select(originalText.GetTextEdit).ToArray(); return new FormattingResult(finalEdits); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs index 11b96afdda8..d4d86a468c9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingPass.cs @@ -10,10 +10,8 @@ using Microsoft.AspNetCore.Razor.Language.Components; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -44,7 +42,7 @@ public async override Task ExecuteAsync(FormattingContext cont var changedContext = context; if (result.Edits.Length > 0) { - var changes = result.Edits.Select(e => e.ToTextChange(originalText)).ToArray(); + var changes = result.Edits.Select(originalText.GetTextChange).ToArray(); changedText = changedText.WithChanges(changes); changedContext = await context.WithTextAsync(changedText).ConfigureAwait(false); @@ -56,11 +54,11 @@ public async override Task ExecuteAsync(FormattingContext cont var edits = FormatRazor(changedContext, syntaxTree); // Compute the final combined set of edits - var formattingChanges = edits.Select(e => e.ToTextChange(changedText)); + var formattingChanges = edits.Select(changedText.GetTextChange); changedText = changedText.WithChanges(formattingChanges); var finalChanges = changedText.GetTextChanges(originalText); - var finalEdits = finalChanges.Select(f => f.ToTextEdit(originalText)).ToArray(); + var finalEdits = finalChanges.Select(originalText.GetTextEdit).ToArray(); return new FormattingResult(finalEdits); } @@ -119,12 +117,7 @@ directiveCode.Children is [RazorDirectiveSyntax directive] && else if (children.TryGetOpenBraceToken(out var brace)) { // If there is no whitespace at all we normalize to a single space - var start = brace.GetRange(source).Start; - var edit = new TextEdit - { - Range = new Range { Start = start, End = start }, - NewText = " " - }; + var edit = VsLspFactory.CreateTextEdit(brace.GetRange(source).Start, " "); edits.Add(edit); return true; @@ -286,14 +279,13 @@ private void TryFormatCSharpBlockStructure(FormattingContext context, List edits, RazorSour } } - static bool IsSingleLineDirective(SyntaxNode node, [NotNullWhen(true)] out SyntaxList? children) + static bool IsSingleLineDirective(SyntaxNode node, out SyntaxList children) { if (node is CSharpCodeBlockSyntax content && node.Parent?.Parent is RazorDirectiveSyntax directive && @@ -345,7 +337,7 @@ static bool IsSingleLineDirective(SyntaxNode node, [NotNullWhen(true)] out Synta return true; } - children = null; + children = default; return false; } } @@ -360,11 +352,11 @@ private static void FormatWhitespaceBetweenDirectiveAndBrace(SyntaxNode node, Ra { // If there is a newline then we want to have just one newline after the directive // and indent the { to match the @ - var edit = new TextEdit - { - Range = node.GetRange(source), - NewText = context.NewLineString + FormattingUtilities.GetIndentationString(directive.GetLinePositionSpan(source).Start.Character, context.Options.InsertSpaces, context.Options.TabSize) - }; + var edit = VsLspFactory.CreateTextEdit( + node.GetRange(source), + context.NewLineString + FormattingUtilities.GetIndentationString( + directive.GetLinePositionSpan(source).Start.Character, context.Options.InsertSpaces, context.Options.TabSize)); + edits.Add(edit); } } @@ -374,11 +366,7 @@ private static void ShrinkToSingleSpace(SyntaxNode node, List edits, R // If there is anything other than one single space then we replace with one space between directive and brace. // // ie, "@code {" will become "@code {" - var edit = new TextEdit - { - Range = node.GetRange(source), - NewText = " " - }; + var edit = VsLspFactory.CreateTextEdit(node.GetRange(source), " "); edits.Add(edit); } @@ -401,11 +389,7 @@ codeRange is not null && newText += FormattingUtilities.GetIndentationString(additionalIndentationLevel, context.Options.InsertSpaces, context.Options.TabSize); } - var edit = new TextEdit - { - NewText = newText, - Range = new Range { Start = openBraceRange.End, End = openBraceRange.End }, - }; + var edit = VsLspFactory.CreateTextEdit(openBraceRange.End, newText); edits.Add(edit); didFormat = true; } @@ -420,22 +404,17 @@ closeBraceRange is not null && { // If we have a directive, then we line the close brace up with it, and ensure // there is a close brace - var edit = new TextEdit - { - NewText = context.NewLineString + FormattingUtilities.GetIndentationString(directiveNode.GetRange(source).Start.Character, context.Options.InsertSpaces, context.Options.TabSize), - Range = new Range { Start = codeRange.End, End = closeBraceRange.Start }, - }; + var edit = VsLspFactory.CreateTextEdit(start: codeRange.End, end: closeBraceRange.Start, + context.NewLineString + FormattingUtilities.GetIndentationString( + directiveNode.GetRange(source).Start.Character, context.Options.InsertSpaces, context.Options.TabSize)); + edits.Add(edit); didFormat = true; } else if (codeRange.End.Line == closeBraceRange.Start.Line) { // Add a Newline between the content and the "}" if one doesn't already exist. - var edit = new TextEdit - { - NewText = context.NewLineString, - Range = new Range { Start = codeRange.End, End = codeRange.End }, - }; + var edit = VsLspFactory.CreateTextEdit(codeRange.End, context.NewLineString); edits.Add(edit); didFormat = true; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs index f7361cee6a9..007250d2bdd 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Formatting/RazorFormattingService.cs @@ -11,9 +11,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; @@ -59,10 +59,10 @@ public async Task FormatAsync( // Razor diagnostics, not the C# diagnostics 🤦‍ if (range is not null) { - var sourceText = codeDocument.GetSourceText(); - if (codeDocument.GetCSharpDocument().Diagnostics.Any(d => d.Span != SourceSpan.Undefined && range.ToLinePositionSpan().OverlapsWith(d.Span.ToLinePositionSpan(sourceText)))) + var sourceText = codeDocument.Source.Text; + if (codeDocument.GetCSharpDocument().Diagnostics.Any(d => d.Span != SourceSpan.Undefined && range.OverlapsWith(sourceText.GetRange(d.Span)))) { - return Array.Empty(); + return []; } } @@ -72,7 +72,7 @@ public async Task FormatAsync( using var context = FormattingContext.Create(uri, documentSnapshot, codeDocument, options, _workspaceFactory); var originalText = context.SourceText; - var result = new FormattingResult(Array.Empty()); + var result = new FormattingResult([]); foreach (var pass in _formattingPasses) { cancellationToken.ThrowIfCancellationRequested(); @@ -89,7 +89,7 @@ public async Task FormatAsync( private static TextEdit[] GetMinimalEdits(SourceText originalText, IEnumerable filteredEdits) { // Make sure the edits actually change something, or its not worth responding - var textChanges = filteredEdits.Select(e => e.ToTextChange(originalText)); + var textChanges = filteredEdits.Select(originalText.GetTextChange); var changedText = originalText.WithChanges(textChanges); if (changedText.ContentEquals(originalText)) { @@ -98,7 +98,7 @@ private static TextEdit[] GetMinimalEdits(SourceText originalText, IEnumerable f.ToTextEdit(originalText)).ToArray(); + var finalEdits = minimalChanges.Select(originalText.GetTextEdit).ToArray(); return finalEdits; } @@ -176,8 +176,7 @@ private async Task ApplyFormattedEditsAsync( { var collapsedEdit = MergeEdits(edits, originalText); if (collapsedEdit.NewText.Length == 0 && - collapsedEdit.Range.Start.Line == collapsedEdit.Range.End.Line && - collapsedEdit.Range.Start.Character == collapsedEdit.Range.End.Character) + collapsedEdit.Range.IsZeroWidth()) { return Array.Empty(); } @@ -199,7 +198,7 @@ internal static TextEdit MergeEdits(TextEdit[] edits, SourceText sourceText) var textChanges = new List(); foreach (var edit in edits) { - var change = new TextChange(edit.Range.ToTextSpan(sourceText), edit.NewText); + var change = new TextChange(sourceText.GetTextSpan(edit.Range), edit.NewText); textChanges.Add(change); } @@ -211,7 +210,7 @@ internal static TextEdit MergeEdits(TextEdit[] edits, SourceText sourceText) var encompassingChange = new TextChange(spanBeforeChange, newText); - return encompassingChange.ToTextEdit(sourceText); + return sourceText.GetTextEdit(encompassingChange); } private static void WrapCSharpSnippets(TextEdit[] snippetEdits) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs index 2c75f6b6dc5..4799f85575e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/GeneratedDocumentPublisher.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Threading; namespace Microsoft.AspNetCore.Razor.LanguageServer; @@ -96,7 +97,7 @@ public void PublishCSharp(ProjectKey projectKey, string filePath, SourceText sou { HostDocumentFilePath = filePath, ProjectKeyId = projectKey.Id, - Changes = textChanges.Select(t => t.ToRazorTextChange()).ToArray(), + Changes = textChanges.Select(static t => t.ToRazorTextChange()).ToArray(), HostDocumentVersion = hostDocumentVersion, PreviousWasEmpty = previouslyPublishedData.SourceText.Length == 0 }; @@ -139,7 +140,7 @@ public void PublishHtml(ProjectKey projectKey, string filePath, SourceText sourc { HostDocumentFilePath = filePath, ProjectKeyId = projectKey.Id, - Changes = textChanges.Select(t => t.ToRazorTextChange()).ToArray(), + Changes = textChanges.Select(static t => t.ToRazorTextChange()).ToArray(), HostDocumentVersion = hostDocumentVersion, PreviousWasEmpty = previouslyPublishedData.SourceText.Length == 0 }; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs index 28cefc408c1..fe063b11312 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Hover/HoverService.cs @@ -16,11 +16,11 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Tooltip; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Editor.Razor; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Text.Adornments; -using VisualStudioMarkupKind = Microsoft.VisualStudio.LanguageServer.Protocol.MarkupKind; +using MarkupKind = Microsoft.VisualStudio.LanguageServer.Protocol.MarkupKind; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Hover; @@ -72,7 +72,7 @@ internal sealed partial class HoverService( if (RazorSyntaxFacts.TryGetFullAttributeNameSpan(codeDocument, positionInfo.HostDocumentIndex, out var originalAttributeRange)) { var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - response.Range = originalAttributeRange.ToRange(sourceText); + response.Range = sourceText.GetRange(originalAttributeRange); } else if (positionInfo.LanguageKind == RazorLanguageKind.CSharp) { @@ -118,7 +118,6 @@ internal sealed partial class HoverService( owner = owner.Parent; } - var position = new Position(location.LineIndex, location.CharacterIndex); var tagHelperDocumentContext = codeDocument.GetTagHelperContext(); // We want to find the parent tag, but looking up ancestors in the tree can find other things, @@ -342,10 +341,10 @@ internal sealed partial class HoverService( return hover; } - private static VisualStudioMarkupKind GetHoverContentFormat(ClientCapabilities clientCapabilities) + private static MarkupKind GetHoverContentFormat(ClientCapabilities clientCapabilities) { var hoverContentFormat = clientCapabilities.TextDocument?.Hover?.ContentFormat; - var hoverKind = hoverContentFormat?.Contains(VisualStudioMarkupKind.Markdown) == true ? VisualStudioMarkupKind.Markdown : VisualStudioMarkupKind.PlainText; + var hoverKind = hoverContentFormat?.Contains(MarkupKind.Markdown) == true ? MarkupKind.Markdown : MarkupKind.PlainText; return hoverKind; } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs index b2cdbc19a05..c575fc47796 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/IDocumentPositionInfoStrategy.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -12,5 +11,9 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer; internal interface IDocumentPositionInfoStrategy { - Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, ILogger logger, CancellationToken cancellationToken); + Task TryGetPositionInfoAsync( + IRazorDocumentMappingService documentMappingService, + DocumentContext documentContext, + Position position, + CancellationToken cancellationToken); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs index 7a1143d1a60..c0debade37d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlayHints/InlayHintService.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Text.Json; -using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; @@ -13,8 +12,8 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Razor.Workspaces.InlayHints; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.InlayHints; @@ -62,7 +61,7 @@ internal sealed class InlayHintService(IRazorDocumentMappingService documentMapp using var _1 = ArrayBuilderPool.GetPooledObject(out var inlayHintsBuilder); foreach (var hint in inlayHints) { - if (hint.Position.TryGetAbsoluteIndex(csharpSourceText, null, out var absoluteIndex) && + if (csharpSourceText.TryGetAbsoluteIndex(hint.Position, out var absoluteIndex) && _documentMappingService.TryMapToHostDocumentPosition(csharpDocument, absoluteIndex, out Position? hostDocumentPosition, out var hostDocumentIndex)) { // We know this C# maps to Razor, but does it map to Razor that we like? diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs index cde07b9b019..9593b528e87 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/InlineCompletion/InlineCompletionEndPoint.cs @@ -78,8 +78,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalInlineCompleti } var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - var linePosition = new LinePosition(request.Position.Line, request.Position.Character); - var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); + var hostDocumentIndex = sourceText.GetPosition(request.Position); var languageKind = _documentMappingService.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); @@ -115,7 +114,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalInlineCompleti foreach (var item in list.Items) { var containsSnippet = item.TextFormat == InsertTextFormat.Snippet; - var range = item.Range ?? new Range { Start = projectedPosition, End = projectedPosition }; + var range = item.Range ?? projectedPosition.ToZeroWidthRange(); if (!_documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), range, out var rangeInRazorDoc)) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LinkedEditingRange/LinkedEditingRangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LinkedEditingRange/LinkedEditingRangeEndpoint.cs index 6e0ca819680..977805958e8 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LinkedEditingRange/LinkedEditingRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/LinkedEditingRange/LinkedEditingRangeEndpoint.cs @@ -1,35 +1,22 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; -using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.CodeAnalysis.Razor.LinkedEditingRange; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.LinkedEditingRange; [RazorLanguageServerEndpoint(Methods.TextDocumentLinkedEditingRangeName)] -internal class LinkedEditingRangeEndpoint : IRazorRequestHandler, ICapabilitiesProvider +internal class LinkedEditingRangeEndpoint(ILoggerFactory loggerFactory) + : IRazorRequestHandler, ICapabilitiesProvider { - private readonly ILogger _logger; - - public LinkedEditingRangeEndpoint(ILoggerFactory loggerFactory) - { - if (loggerFactory is null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - _logger = loggerFactory.GetOrCreateLogger(); - } + private readonly ILogger _logger = loggerFactory.GetOrCreateLogger(); public bool MutatesSolutionState => false; @@ -62,9 +49,9 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LinkedEditingRangeParams return null; } - if (LinkedEditingRangeHelper.GetLinkedSpans(request.Position.ToLinePosition(), codeDocument, _logger) is { } linkedSpans && linkedSpans.Length == 2) + if (LinkedEditingRangeHelper.GetLinkedSpans(request.Position.ToLinePosition(), codeDocument) is { } linkedSpans && linkedSpans.Length == 2) { - var ranges = new Range[2] { linkedSpans[0].ToRange(), linkedSpans[1].ToRange() }; + var ranges = new[] { linkedSpans[0].ToRange(), linkedSpans[1].ToRange() }; return new LinkedEditingRanges { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs index e00d1fed49c..f076c975592 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs @@ -236,7 +236,7 @@ private async Task TryMapCodeAsync( if (insertionSpan is not null) { var textSpan = new TextSpan(insertionSpan.Value, 0); - var edit = new TextEdit { NewText = nodeToMap.ToFullString(), Range = textSpan.ToRange(sourceText) }; + var edit = VsLspFactory.CreateTextEdit(sourceText.GetRange(textSpan), nodeToMap.ToFullString()); var textDocumentEdit = new TextDocumentEdit { @@ -440,11 +440,7 @@ async Task TryProcessEditAsync( return false; } - var textEdit = new TextEdit - { - Range = hostDocumentRange, - NewText = documentEdit.NewText - }; + var textEdit = VsLspFactory.CreateTextEdit(hostDocumentRange, documentEdit.NewText); var textDocumentEdit = new TextDocumentEdit { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/Mappers/InsertMapper.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/Mappers/InsertMapper.cs index 9d971530fe4..d5981471507 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/Mappers/InsertMapper.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/Mappers/InsertMapper.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.MapCode.Mappers; @@ -47,14 +48,14 @@ private static bool TryGetFocusedInsertionPoint( } // Verify that the focus area is within the document. - if (!focusArea.Range.Start.IsValid(sourceText)) + if (!sourceText.IsValidPosition(focusArea.Range.Start)) { insertionPoint = 0; return false; } // Ensure we don't insert in the middle of a node. - var node = documentRoot.FindNode(focusArea.Range.ToTextSpan(sourceText), includeWhitespace: true); + var node = documentRoot.FindNode(sourceText.GetTextSpan(focusArea.Range), includeWhitespace: true); if (node is null) { insertionPoint = 0; @@ -68,7 +69,7 @@ private static bool TryGetFocusedInsertionPoint( var line = sourceText.Lines[focusArea.Range.Start.Line]; if (line.GetFirstNonWhitespaceOffset() is null) { - insertionPoint = focusArea.Range.ToTextSpan(sourceText).Start; + insertionPoint = sourceText.GetTextSpan(focusArea.Range).Start; return true; } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs index cc14c9690bb..b4e6da2b476 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorLanguageQueryEndpoint.cs @@ -43,8 +43,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(RazorLanguageQueryParams var codeDocument = await documentSnapshot.GetGeneratedOutputAsync().ConfigureAwait(false); var sourceText = await documentSnapshot.GetTextAsync().ConfigureAwait(false); - var linePosition = new LinePosition(request.Position.Line, request.Position.Character); - var hostDocumentIndex = sourceText.Lines.GetPosition(linePosition); + var hostDocumentIndex = sourceText.GetPosition(request.Position); var responsePosition = request.Position; if (codeDocument.IsUnsupported()) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs index bae9f557930..18f308dc13c 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Mapping/RazorMapToDocumentRangesEndpoint.cs @@ -9,8 +9,9 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CommonLanguageServerProtocol.Framework; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Mapping; @@ -65,7 +66,7 @@ public Uri GetTextDocumentIdentifier(RazorMapToDocumentRangesParams request) !_documentMappingService.TryMapToHostDocumentRange(codeDocument.GetCSharpDocument(), projectedRange, request.MappingBehavior, out var originalRange)) { // All language queries on unsupported documents return Html. This is equivalent to what pre-VSCode Razor was capable of. - ranges[i] = RangeExtensions.UndefinedRange; + ranges[i] = VsLspFactory.UndefinedRange; continue; } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Microsoft.AspNetCore.Razor.LanguageServer.csproj b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Microsoft.AspNetCore.Razor.LanguageServer.csproj index ee5bd5defbc..8c0b64042b4 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Microsoft.AspNetCore.Razor.LanguageServer.csproj +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Microsoft.AspNetCore.Razor.LanguageServer.csproj @@ -10,7 +10,6 @@ - diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs index bf829aade9e..3bd88203f85 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/PreferAttributeNameDocumentPositionInfoStrategy.cs @@ -4,9 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer; @@ -20,23 +19,28 @@ internal class PreferAttributeNameDocumentPositionInfoStrategy : IDocumentPositi { public static IDocumentPositionInfoStrategy Instance { get; } = new PreferAttributeNameDocumentPositionInfoStrategy(); - public async Task TryGetPositionInfoAsync(IRazorDocumentMappingService documentMappingService, DocumentContext documentContext, Position position, ILogger logger, CancellationToken cancellationToken) + public async Task TryGetPositionInfoAsync( + IRazorDocumentMappingService documentMappingService, + DocumentContext documentContext, + Position position, + CancellationToken cancellationToken) { var codeDocument = await documentContext.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (position.TryGetAbsoluteIndex(sourceText, logger, out var absoluteIndex)) + if (sourceText.TryGetAbsoluteIndex(position, out var absoluteIndex)) { // First, lets see if we should adjust the location to get a better result from C#. For example given // where | is the cursor, we would be unable to map that location to C#. If we pretend the caret was 3 characters to the right though, // in the actual component property name, then the C# server would give us a result, so we fake it. if (RazorSyntaxFacts.TryGetAttributeNameAbsoluteIndex(codeDocument, absoluteIndex, out var attributeNameIndex)) { - sourceText.GetLineAndOffset(attributeNameIndex, out var line, out var offset); - position = new Position(line, offset); + position = sourceText.GetPosition(attributeNameIndex); } } // We actually don't need a different projection strategy, we just wanted to move the caret position - return await DefaultDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync(documentMappingService, documentContext, position, logger, cancellationToken).ConfigureAwait(false); + return await DefaultDocumentPositionInfoStrategy.Instance + .TryGetPositionInfoAsync(documentMappingService, documentContext, position, cancellationToken) + .ConfigureAwait(false); } } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorSyntaxFacts.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorSyntaxFacts.cs index 94bb579c11d..1e8c122d9f1 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorSyntaxFacts.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/RazorSyntaxFacts.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.LanguageServer; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs index 75f50f0bccf..761ae07fc07 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Refactoring/RenameEndpoint.cs @@ -320,19 +320,11 @@ private static TextEdit[] CreateEditsForMarkupTagHelperElement(MarkupTagHelperEl { using var _ = ListPool.GetPooledObject(out var edits); - edits.Add(new() - { - Range = element.StartTag.Name.GetRange(codeDocument.Source), - NewText = newName - }); + edits.Add(VsLspFactory.CreateTextEdit(element.StartTag.Name.GetRange(codeDocument.Source), newName)); if (element.EndTag is MarkupTagHelperEndTagSyntax endTag) { - edits.Add(new TextEdit() - { - Range = endTag.Name.GetRange(codeDocument.Source), - NewText = newName, - }); + edits.Add(VsLspFactory.CreateTextEdit(endTag.Name.GetRange(codeDocument.Source), newName)); } return [.. edits]; diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs index 7015151ae10..841b15ba463 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/Services/LSPCSharpSemanticTokensProvider.cs @@ -14,6 +14,8 @@ using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Razor.Workspaces.Protocol.SemanticTokens; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; @@ -48,11 +50,7 @@ internal class LSPCSharpSemanticTokensProvider(LanguageServerFeatureOptions lang // Likely the server doesn't support the new endpoint, fallback to the original one if (csharpResponse?.Tokens is null && csharpRanges.Length > 1) { - var minimalRange = new Range - { - Start = csharpRanges[0].Start, - End = csharpRanges[^1].End - }; + var minimalRange = VsLspFactory.CreateRange(csharpRanges[0].Start, csharpRanges[^1].End); var newParams = new ProvideSemanticTokensRangesParams( parameter.TextDocument, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs index 0096e0b3df5..b290be86aef 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/WrapWithTag/WrapWithTagEndpoint.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.WrapWithTag; @@ -54,7 +54,8 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(WrapWithTagParams reques } var sourceText = await documentContext.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (request.Range?.Start.TryGetAbsoluteIndex(sourceText, _logger, out var hostDocumentIndex) != true) + if (request.Range?.Start is not { } start || + !sourceText.TryGetAbsoluteIndex(start, out var hostDocumentIndex)) { return null; } @@ -81,13 +82,13 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(WrapWithTagParams reques //

[|@currentCount|]

var tree = await documentContext.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var requestSpan = request.Range.ToTextSpan(sourceText); + var requestSpan = sourceText.GetTextSpan(request.Range); var node = tree.Root.FindNode(requestSpan, includeWhitespace: false, getInnermostNodeForTie: true); if (node?.FirstAncestorOrSelf() is { Parent: CSharpCodeBlockSyntax codeBlock } && (requestSpan == codeBlock.FullSpan || requestSpan.Length == 0)) { // Pretend we're in Html so the rest of the logic can continue - request.Range = codeBlock.FullSpan.ToRange(sourceText); + request.Range = sourceText.GetRange(codeBlock.FullSpan); languageKind = RazorLanguageKind.Html; } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs index 668ee49d4e9..03a99f532c1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/AbstractRazorDocumentMappingService.cs @@ -18,7 +18,6 @@ using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; -using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.CodeAnalysis.Razor.DocumentMapping; @@ -41,13 +40,13 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument foreach (var edit in generatedDocumentEdits) { var range = edit.Range; - if (!IsRangeWithinDocument(range, generatedDocumentSourceText)) + if (!IsRangeWithinDocument(range.ToLinePositionSpan(), generatedDocumentSourceText)) { continue; } - var startSync = range.Start.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out var startIndex); - var endSync = range.End.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out var endIndex); + var startSync = generatedDocumentSourceText.TryGetAbsoluteIndex(range.Start, out var startIndex); + var endSync = generatedDocumentSourceText.TryGetAbsoluteIndex(range.End, out var endIndex); if (startSync is false || endSync is false) { break; @@ -63,11 +62,7 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument // between this edit and the previous one, because the normalization will have swallowed it. See // below for a more info. var newText = (lastNewLineAddedToLine == range.Start.Line ? " " : "") + edit.NewText; - hostDocumentEdits.Add(new TextEdit() - { - NewText = newText, - Range = new Range { Start = hostDocumentStart!, End = hostDocumentEnd! }, - }); + hostDocumentEdits.Add(VsLspFactory.CreateTextEdit(hostDocumentStart!, hostDocumentEnd!, newText)); continue; } @@ -100,9 +95,9 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument // so we can ignore all but the last line. This assert ensures that is true, just in case something changes in Roslyn Debug.Assert(lastNewLine == 0 || edit.NewText[..(lastNewLine - 1)].All(c => c == '\r' || c == '\n'), "We are throwing away part of an edit that has more than just empty lines!"); - var proposedRange = new Range { Start = new Position(range.End.Line, 0), End = new Position(range.End.Line, range.End.Character) }; - startSync = proposedRange.Start.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out startIndex); - endSync = proposedRange.End.TryGetAbsoluteIndex(generatedDocumentSourceText, _logger, out endIndex); + var proposedRange = VsLspFactory.CreateSingleLineRange(range.End.Line, character: 0, length: range.End.Character); + startSync = generatedDocumentSourceText.TryGetAbsoluteIndex(proposedRange.Start, out startIndex); + endSync = generatedDocumentSourceText.TryGetAbsoluteIndex(proposedRange.End, out endIndex); if (startSync is false || endSync is false) { break; @@ -113,11 +108,7 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument if (mappedStart && mappedEnd) { - hostDocumentEdits.Add(new TextEdit() - { - NewText = edit.NewText[lastNewLine..], - Range = new Range { Start = hostDocumentStart!, End = hostDocumentEnd! }, - }); + hostDocumentEdits.Add(VsLspFactory.CreateTextEdit(hostDocumentStart!, hostDocumentEnd!, edit.NewText[lastNewLine..])); continue; } } @@ -170,21 +161,15 @@ public TextEdit[] GetHostDocumentEdits(IRazorGeneratedDocument generatedDocument // If we already added a newline to this line, then we don't want to add another one, but // we do need to add a space between this edit and the previous one, because the normalization // will have swallowed it. - hostDocumentEdits.Add(new TextEdit() - { - NewText = " " + edit.NewText, - Range = new Range { Start = hostDocumentIndex, End = hostDocumentIndex } - }); + hostDocumentEdits.Add(VsLspFactory.CreateTextEdit(hostDocumentIndex, " " + edit.NewText)); } else { // Otherwise, add a newline and the real content, and remember where we added it lastNewLineAddedToLine = range.Start.Line; - hostDocumentEdits.Add(new TextEdit() - { - NewText = Environment.NewLine + new string(' ', range.Start.Character) + edit.NewText, - Range = new Range { Start = hostDocumentIndex, End = hostDocumentIndex } - }); + hostDocumentEdits.Add(VsLspFactory.CreateTextEdit( + hostDocumentIndex, + Environment.NewLine + new string(' ', range.Start.Character) + edit.NewText)); } continue; @@ -243,20 +228,20 @@ public bool TryMapToGeneratedDocumentRange(IRazorGeneratedDocument generatedDocu return false; } - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var range = hostDocumentRange; if (!IsRangeWithinDocument(range, sourceText)) { return false; } - if (!range.Start.TryGetAbsoluteIndex(sourceText, _logger, out var startIndex) || + if (!sourceText.TryGetAbsoluteIndex(range.Start, out var startIndex) || !TryMapToGeneratedDocumentPosition(generatedDocument, startIndex, out var generatedRangeStart, out var _)) { return false; } - if (!range.End.TryGetAbsoluteIndex(sourceText, _logger, out var endIndex) || + if (!sourceText.TryGetAbsoluteIndex(range.End, out var endIndex) || !TryMapToGeneratedDocumentPosition(generatedDocument, endIndex, out var generatedRangeEnd, out var _)) { return false; @@ -322,8 +307,7 @@ public bool TryMapToHostDocumentPosition(IRazorGeneratedDocument generatedDocume var distanceIntoGeneratedSpan = generatedDocumentIndex - generatedAbsoluteIndex; hostDocumentIndex = mapping.OriginalSpan.AbsoluteIndex + distanceIntoGeneratedSpan; - var originalLocation = codeDocument.Source.Text.Lines.GetLinePosition(hostDocumentIndex); - hostDocumentPosition = new LinePosition(originalLocation.Line, originalLocation.Character); + hostDocumentPosition = codeDocument.Source.Text.GetLinePosition(hostDocumentIndex); return true; } @@ -372,9 +356,9 @@ private static bool TryMapToGeneratedDocumentPositionInternal(IRazorGeneratedDoc // The "next" C# location is only valid if it is on the same line in the source document // as the requested position. - codeDocument.GetSourceText().GetLineAndOffset(hostDocumentIndex, out var hostDocumentLine, out _); + var hostDocumentLinePosition = codeDocument.Source.Text.GetLinePosition(hostDocumentIndex); - if (mapping.OriginalSpan.LineIndex == hostDocumentLine) + if (mapping.OriginalSpan.LineIndex == hostDocumentLinePosition.Line) { generatedIndex = mapping.GeneratedSpan.AbsoluteIndex; generatedPosition = GetGeneratedPosition(generatedDocument, generatedIndex); @@ -392,7 +376,7 @@ private static bool TryMapToGeneratedDocumentPositionInternal(IRazorGeneratedDoc static LinePosition GetGeneratedPosition(IRazorGeneratedDocument generatedDocument, int generatedIndex) { var generatedSource = GetGeneratedSourceText(generatedDocument); - return generatedSource.Lines.GetLinePosition(generatedIndex); + return generatedSource.GetLinePosition(generatedIndex); } } @@ -578,13 +562,13 @@ private bool TryMapToHostDocumentRangeStrict(IRazorGeneratedDocument generatedDo return false; } - if (!range.Start.TryGetAbsoluteIndex(generatedSourceText, _logger, out var startIndex) || + if (!generatedSourceText.TryGetAbsoluteIndex(range.Start, out var startIndex) || !TryMapToHostDocumentPosition(generatedDocument, startIndex, out var hostDocumentStart, out _)) { return false; } - if (!range.End.TryGetAbsoluteIndex(generatedSourceText, _logger, out var endIndex) || + if (!generatedSourceText.TryGetAbsoluteIndex(range.End, out var endIndex) || !TryMapToHostDocumentPosition(generatedDocument, endIndex, out var hostDocumentEnd, out _)) { return false; @@ -617,10 +601,10 @@ private bool TryMapToHostDocumentRangeInclusive(IRazorGeneratedDocument generate return false; } - var startIndex = generatedDocumentRange.Start.GetRequiredAbsoluteIndex(generatedSourceText); + var startIndex = generatedSourceText.GetRequiredAbsoluteIndex(generatedDocumentRange.Start); var startMappedDirectly = TryMapToHostDocumentPosition(generatedDocument, startIndex, out var hostDocumentStart, out _); - var endIndex = generatedDocumentRange.End.GetRequiredAbsoluteIndex(generatedSourceText); + var endIndex = generatedSourceText.GetRequiredAbsoluteIndex(generatedDocumentRange.End); var endMappedDirectly = TryMapToHostDocumentPosition(generatedDocument, endIndex, out var hostDocumentEnd, out _); if (startMappedDirectly && endMappedDirectly && hostDocumentStart <= hostDocumentEnd) @@ -634,17 +618,21 @@ private bool TryMapToHostDocumentRangeInclusive(IRazorGeneratedDocument generate if (startMappedDirectly) { // Start of generated range intersects with a mapping - candidateMappings.AddRange(generatedDocument.SourceMappings.Where(mapping => IntersectsWith(startIndex, mapping.GeneratedSpan))); + candidateMappings.AddRange( + generatedDocument.SourceMappings.Where(mapping => IntersectsWith(startIndex, mapping.GeneratedSpan))); } else if (endMappedDirectly) { // End of generated range intersects with a mapping - candidateMappings.AddRange(generatedDocument.SourceMappings.Where(mapping => IntersectsWith(endIndex, mapping.GeneratedSpan))); + candidateMappings.AddRange( + generatedDocument.SourceMappings.Where(mapping => IntersectsWith(endIndex, mapping.GeneratedSpan))); } else { // Our range does not intersect with any mapping; we should see if it overlaps generated locations - candidateMappings.AddRange(generatedDocument.SourceMappings.Where(mapping => Overlaps(generatedDocumentRange.ToTextSpan(generatedSourceText), mapping.GeneratedSpan))); + candidateMappings.AddRange( + generatedDocument.SourceMappings + .Where(mapping => Overlaps(generatedSourceText.GetTextSpan(generatedDocumentRange), mapping.GeneratedSpan))); } if (candidateMappings.Count == 1) @@ -652,7 +640,7 @@ private bool TryMapToHostDocumentRangeInclusive(IRazorGeneratedDocument generate // We're intersecting or overlapping a single mapping, lets choose that. var mapping = candidateMappings[0]; - hostDocumentRange = ConvertMapping(codeDocument.Source, mapping); + hostDocumentRange = codeDocument.Source.Text.GetLinePositionSpan(mapping.OriginalSpan); return true; } else @@ -673,14 +661,6 @@ bool IntersectsWith(int position, SourceSpan span) { return unchecked((uint)(position - span.AbsoluteIndex) <= (uint)span.Length); } - - static LinePositionSpan ConvertMapping(RazorSourceDocument sourceDocument, SourceMapping mapping) - { - var startLocation = sourceDocument.Text.Lines.GetLinePosition(mapping.OriginalSpan.AbsoluteIndex); - var endLocation = sourceDocument.Text.Lines.GetLinePosition(mapping.OriginalSpan.AbsoluteIndex + mapping.OriginalSpan.Length); - var convertedRange = new LinePositionSpan(startLocation, endLocation); - return convertedRange; - } } private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generatedDocument, LinePositionSpan generatedDocumentRange, out LinePositionSpan hostDocumentRange) @@ -706,7 +686,7 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated return false; } - var generatedRangeAsSpan = generatedDocumentRange.ToTextSpan(generatedSourceText); + var generatedRangeAsSpan = generatedSourceText.GetTextSpan(generatedDocumentRange); SourceMapping? mappingBeforeGeneratedRange = null; SourceMapping? mappingAfterGeneratedRange = null; @@ -738,15 +718,14 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated var sourceDocument = codeDocument.Source; var originalSpanBeforeGeneratedRange = mappingBeforeGeneratedRange.OriginalSpan; var originalEndBeforeGeneratedRange = originalSpanBeforeGeneratedRange.AbsoluteIndex + originalSpanBeforeGeneratedRange.Length; - var originalEndPositionBeforeGeneratedRange = sourceDocument.Text.Lines.GetLinePosition(originalEndBeforeGeneratedRange); - var inferredStartPosition = new LinePosition(originalEndPositionBeforeGeneratedRange.Line, originalEndPositionBeforeGeneratedRange.Character); + var inferredStartPosition = sourceDocument.Text.GetLinePosition(originalEndBeforeGeneratedRange); if (mappingAfterGeneratedRange != null) { // There's a mapping after the "generated range" lets use its start position as our inferred end position. var originalSpanAfterGeneratedRange = mappingAfterGeneratedRange.OriginalSpan; - var originalStartPositionAfterGeneratedRange = sourceDocument.Text.Lines.GetLinePosition(originalSpanAfterGeneratedRange.AbsoluteIndex); + var originalStartPositionAfterGeneratedRange = sourceDocument.Text.GetLinePosition(originalSpanAfterGeneratedRange.AbsoluteIndex); // The mapping in the generated file is after the start, but when mapped back to the host file that may not be true if (originalStartPositionAfterGeneratedRange >= inferredStartPosition) @@ -760,7 +739,7 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated Debug.Assert(sourceDocument.Text.Length > 0, "Source document length should be greater than 0 here because there's a mapping before us"); - var endOfDocumentPosition = sourceDocument.Text.Lines.GetLinePosition(sourceDocument.Text.Length); + var endOfDocumentPosition = sourceDocument.Text.GetLinePosition(sourceDocument.Text.Length); Debug.Assert(endOfDocumentPosition >= inferredStartPosition, "Some how we found a start position that is after the end of the document?"); @@ -770,9 +749,6 @@ private bool TryMapToHostDocumentRangeInferred(IRazorGeneratedDocument generated private static bool s_haveAsserted = false; - private bool IsRangeWithinDocument(Range range, SourceText sourceText) - => IsRangeWithinDocument(range.ToLinePositionSpan(), sourceText); - private bool IsRangeWithinDocument(LinePositionSpan range, SourceText sourceText) { // This might happen when the document that ranges were created against was not the same as the document we're consulting. @@ -789,7 +765,7 @@ private bool IsRangeWithinDocument(LinePositionSpan range, SourceText sourceText static bool IsPositionWithinDocument(LinePosition linePosition, SourceText sourceText) { - return sourceText.TryGetAbsoluteIndex(linePosition.Line, linePosition.Character, out _); + return sourceText.TryGetAbsoluteIndex(linePosition, out _); } } @@ -891,12 +867,7 @@ private TextEdit[] RemapTextEditsCore(Uri generatedDocumentUri, RazorCodeDocumen continue; } - var edit = new TextEdit() - { - Range = originalRange, - NewText = edits[i].NewText - }; - + var edit = VsLspFactory.CreateTextEdit(originalRange, edits[i].NewText); remappedEdits.Add(edit); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs index e5280a6dcc0..0fdc80e24b4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DocumentMapping/IRazorDocumentMappingServiceExtensions.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; @@ -37,8 +36,7 @@ public static DocumentPositionInfo GetPositionInfo( SourceText sourceText, int hostDocumentIndex) { - sourceText.GetLineAndOffset(hostDocumentIndex, out var line, out var character); - var position = new Position(line, character); + var position = sourceText.GetPosition(hostDocumentIndex); var languageKind = service.GetLanguageKind(codeDocument, hostDocumentIndex, rightAssociative: false); if (languageKind is not RazorLanguageKind.Razor) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IEnumerableExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/EnumerableExtensions.cs similarity index 56% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IEnumerableExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/EnumerableExtensions.cs index cd1dc30ae31..7039e201bfa 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IEnumerableExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/EnumerableExtensions.cs @@ -6,10 +6,9 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces; -internal static class IEnumerableExtensions +internal static class EnumerableExtensions { - internal static IEnumerable WithoutNull(this IEnumerable ts) - { - return ts.Where(t => t != null).Select(t => t!); - } + internal static IEnumerable WhereNotNull(this IEnumerable source) + where T : class + => source.Where(static t => t is not null)!; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionExtensions.cs index e8d877c4ff5..45ae3813eeb 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionExtensions.cs @@ -1,24 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using RLSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Text; internal static class LinePositionExtensions { - public static Position ToPosition(this LinePosition linePosition) - => new Position(linePosition.Line, linePosition.Character); - - public static RLSP.Position ToRLSPPosition(this LinePosition linePosition) - => new RLSP.Position(linePosition.Line, linePosition.Character); - - public static bool TryGetAbsoluteIndex(this LinePosition position, SourceText sourceText, ILogger logger, out int absoluteIndex) - => sourceText.TryGetAbsoluteIndex(position.Line, position.Character, logger, out absoluteIndex); + public static void Deconstruct(this LinePosition linePosition, out int line, out int character) + => (line, character) = (linePosition.Line, linePosition.Character); - public static int GetRequiredAbsoluteIndex(this LinePosition position, SourceText sourceText, ILogger? logger = null) - => sourceText.GetRequiredAbsoluteIndex(position.Line, position.Character, logger); + public static LinePositionSpan ToZeroWidthSpan(this LinePosition linePosition) + => new(linePosition, linePosition); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionSpanExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionSpanExtensions.cs index b446affd1be..3cd11ef1405 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionSpanExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/LinePositionSpanExtensions.cs @@ -1,41 +1,26 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using RLSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Text; internal static class LinePositionSpanExtensions { - public static Range ToRange(this LinePositionSpan linePositionSpan) - => new() - { - Start = linePositionSpan.Start.ToPosition(), - End = linePositionSpan.End.ToPosition() - }; - - public static RLSP.Range ToRLSPRange(this LinePositionSpan linePositionSpan) - => new RLSP.Range - { - Start = linePositionSpan.Start.ToRLSPPosition(), - End = linePositionSpan.End.ToRLSPPosition() - }; + public static void Deconstruct(this LinePositionSpan linePositionSpan, out LinePosition start, out LinePosition end) + => (start, end) = (linePositionSpan.Start, linePositionSpan.End); - public static TextSpan ToTextSpan(this LinePositionSpan linePositionSpan, SourceText sourceText) - => sourceText.GetTextSpan(linePositionSpan.Start.Line, linePositionSpan.Start.Character, linePositionSpan.End.Line, linePositionSpan.End.Character); + public static void Deconstruct(this LinePositionSpan linePositionSpan, out int startLine, out int startCharacter, out int endLine, out int endCharacter) + => (startLine, startCharacter, endLine, endCharacter) = (linePositionSpan.Start.Line, linePositionSpan.Start.Character, linePositionSpan.End.Line, linePositionSpan.End.Character); - public static bool OverlapsWith(this LinePositionSpan range, LinePositionSpan other) + public static bool OverlapsWith(this LinePositionSpan span, LinePositionSpan other) { - var overlapStart = range.Start; - if (range.Start.CompareTo(other.Start) < 0) + var overlapStart = span.Start; + if (span.Start.CompareTo(other.Start) < 0) { overlapStart = other.Start; } - var overlapEnd = range.End; - if (range.End.CompareTo(other.End) > 0) + var overlapEnd = span.End; + if (span.End.CompareTo(other.End) > 0) { overlapEnd = other.End; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/PositionExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/PositionExtensions.cs deleted file mode 100644 index dc71fc530b5..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/PositionExtensions.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using RLSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -internal static class PositionExtensions -{ - public static LinePosition ToLinePosition(this Position position) - => new LinePosition(position.Line, position.Character); - - public static LinePosition ToLinePosition(this RLSP.Position position) - => new LinePosition(position.Line, position.Character); - - public static bool TryGetAbsoluteIndex(this Position position, SourceText sourceText, ILogger? logger, out int absoluteIndex) - { - if (position is null) - { - throw new ArgumentNullException(nameof(position)); - } - - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } - - return sourceText.TryGetAbsoluteIndex(position.Line, position.Character, logger, out absoluteIndex); - } - - - public static bool TryGetSourceLocation( - this Position position, - SourceText sourceText, - ILogger? logger, - [NotNullWhen(true)] out SourceLocation? sourceLocation) - { - if (!position.TryGetAbsoluteIndex(sourceText, logger, out var absoluteIndex)) - { - sourceLocation = null; - return false; - } - - sourceLocation = new SourceLocation(absoluteIndex, position.Line, position.Character); - return true; - } - - public static int GetRequiredAbsoluteIndex(this Position position, SourceText sourceText, ILogger? logger) - { - if (!position.TryGetAbsoluteIndex(sourceText, logger, out var absoluteIndex)) - { - throw new InvalidOperationException(); - } - - return absoluteIndex; - } - - public static int CompareTo(this Position position, Position other) - { - if (position is null) - { - throw new ArgumentNullException(nameof(position)); - } - - if (other is null) - { - throw new ArgumentNullException(nameof(other)); - } - - var result = position.Line.CompareTo(other.Line); - return result != 0 ? result : position.Character.CompareTo(other.Character); - } - - public static bool IsValid(this Position position, SourceText sourceText) - { - if (position is null) - { - throw new ArgumentNullException(nameof(position)); - } - - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } - - return sourceText.TryGetAbsoluteIndex(position.Line, position.Character, logger: null, out _); - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs index 129b7991c60..d4e5d081633 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/ProjectExtensions.cs @@ -1,31 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; +using Microsoft.AspNetCore.Razor; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis; internal static class ProjectExtensions { internal static Document GetRequiredDocument(this Project project, DocumentId documentId) { - if (project is null) - { - throw new ArgumentNullException(nameof(project)); - } - - if (documentId is null) - { - throw new ArgumentNullException(nameof(documentId)); - } - - var document = project.GetDocument(documentId); - - if (document is null) - { - throw new InvalidOperationException($"The document {documentId} did not exist in {project.Name}"); - } - - return document; + return project.GetDocument(documentId) + ?? ThrowHelper.ThrowInvalidOperationException($"The document {documentId} did not exist in {project.Name}"); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RangeExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RangeExtensions.cs deleted file mode 100644 index 4f3504b6f8f..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RangeExtensions.cs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; -using RLSP = Roslyn.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -internal static class RangeExtensions -{ - public static readonly Range UndefinedRange = new() - { - Start = new Position(-1, -1), - End = new Position(-1, -1) - }; - - public static bool IntersectsOrTouches(this Range range, Range other) - { - if (range.IsBefore(other)) - { - return false; - } - - if (range.IsAfter(other)) - { - return false; - } - - return true; - } - - private static bool IsBefore(this Range range, Range other) => - range.End.Line < other.Start.Line || range.End.Line == other.Start.Line && range.End.Character < other.Start.Character; - - private static bool IsAfter(this Range range, Range other) => - other.End.Line < range.Start.Line || other.End.Line == range.Start.Line && other.End.Character < range.Start.Character; - - public static bool OverlapsWith(this Range range, Range other) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - if (other is null) - { - throw new ArgumentNullException(nameof(other)); - } - - return range.ToLinePositionSpan().OverlapsWith(other.ToLinePositionSpan()); - } - - public static bool LineOverlapsWith(this Range range, Range other) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - if (other is null) - { - throw new ArgumentNullException(nameof(other)); - } - - var overlapStart = range.Start.Line; - if (range.Start.Line.CompareTo(other.Start.Line) < 0) - { - overlapStart = other.Start.Line; - } - - var overlapEnd = range.End.Line; - if (range.End.Line.CompareTo(other.End.Line) > 0) - { - overlapEnd = other.End.Line; - } - - return overlapStart.CompareTo(overlapEnd) <= 0; - } - - public static bool Contains(this Range range, Range other) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - if (other is null) - { - throw new ArgumentNullException(nameof(other)); - } - - return range.Start.CompareTo(other.Start) <= 0 && range.End.CompareTo(other.End) >= 0; - } - - public static bool SpansMultipleLines(this Range range) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - return range.Start.Line != range.End.Line; - } - - public static TextSpan ToTextSpan(this Range range, SourceText sourceText) - => sourceText.GetTextSpan(range.Start.Line, range.Start.Character, range.End.Line, range.End.Character); - - public static LinePositionSpan ToLinePositionSpan(this Range range) - => new LinePositionSpan(range.Start.ToLinePosition(), range.End.ToLinePosition()); - - public static LinePositionSpan ToLinePositionSpan(this RLSP.Range range) - => new LinePositionSpan(range.Start.ToLinePosition(), range.End.ToLinePosition()); - - public static bool IsUndefined(this Range range) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - return range == UndefinedRange; - } - - public static int CompareTo(this Range range1, Range range2) - { - var result = range1.Start.CompareTo(range2.Start); - - if (result == 0) - { - result = range1.End.CompareTo(range2.End); - } - - return result; - } - - public static string ToDisplayString(this Range range) - { - return $"({range.Start.Line}, {range.Start.Character})-({range.End.Line}, {range.End.Character})"; - } - - public static TextSpan AsTextSpan(this Range range, SourceText sourceText) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } - - var start = sourceText.Lines[range.Start.Line].Start + range.Start.Character; - var end = sourceText.Lines[range.End.Line].Start + range.End.Character; - return new TextSpan(start, end - start); - } - - public static Range? Overlap(this Range range, Range other) - { - if (range is null) - { - throw new ArgumentNullException(nameof(range)); - } - - if (other is null) - { - throw new ArgumentNullException(nameof(other)); - } - - var overlapStart = range.Start; - if (range.Start.CompareTo(other.Start) < 0) - { - overlapStart = other.Start; - } - - var overlapEnd = range.End; - if (range.End.CompareTo(other.End) > 0) - { - overlapEnd = other.End; - } - - // Empty ranges do not overlap with any range. - if (overlapStart.CompareTo(overlapEnd) < 0) - { - return new Range() - { - Start = overlapStart, - End = overlapEnd, - }; - } - - return null; - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs index 536f0f2124c..c542c6e3cf3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorCodeDocumentExtensions.cs @@ -1,100 +1,71 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Diagnostics; using System.Linq; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; +using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Text; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.AspNetCore.Razor.Language; internal static class RazorCodeDocumentExtensions { - private static readonly object s_cSharpSourceTextKey = new(); + private static readonly object s_csharpSourceTextKey = new(); private static readonly object s_htmlSourceTextKey = new(); - public static SourceText GetSourceText(this RazorCodeDocument document) - { - if (document is null) - { - throw new ArgumentNullException(nameof(document)); - } - - return document.Source.Text; - } - public static SourceText GetCSharpSourceText(this RazorCodeDocument document) { - if (document is null) - { - throw new ArgumentNullException(nameof(document)); - } - - var sourceTextObj = document.Items[s_cSharpSourceTextKey]; - if (sourceTextObj is null) + if (!document.Items.TryGetValue(s_csharpSourceTextKey, out SourceText? sourceText)) { var csharpDocument = document.GetCSharpDocument(); - var sourceText = SourceText.From(csharpDocument.GeneratedCode); - document.Items[s_cSharpSourceTextKey] = sourceText; + sourceText = SourceText.From(csharpDocument.GeneratedCode); + document.Items[s_csharpSourceTextKey] = sourceText; return sourceText; } - return (SourceText)sourceTextObj; + return sourceText.AssumeNotNull(); } public static SourceText GetHtmlSourceText(this RazorCodeDocument document) { - if (document is null) - { - throw new ArgumentNullException(nameof(document)); - } - - var sourceTextObj = document.Items[s_htmlSourceTextKey]; - if (sourceTextObj is null) + if (!document.Items.TryGetValue(s_htmlSourceTextKey, out SourceText? sourceText)) { var htmlDocument = document.GetHtmlDocument(); - var sourceText = SourceText.From(htmlDocument.GeneratedCode); + sourceText = SourceText.From(htmlDocument.GeneratedCode); document.Items[s_htmlSourceTextKey] = sourceText; return sourceText; } - return (SourceText)sourceTextObj; + return sourceText.AssumeNotNull(); } public static SourceText GetGeneratedSourceText(this RazorCodeDocument document, IRazorGeneratedDocument generatedDocument) - { - if (generatedDocument is RazorCSharpDocument) - { - return GetCSharpSourceText(document); - } - else if (generatedDocument is RazorHtmlDocument) + => generatedDocument switch { - return GetHtmlSourceText(document); - } - - throw new InvalidOperationException("Unknown generated document type"); - } + RazorCSharpDocument => document.GetCSharpSourceText(), + RazorHtmlDocument => document.GetHtmlSourceText(), + _ => ThrowHelper.ThrowInvalidOperationException("Unknown generated document type"), + }; public static IRazorGeneratedDocument GetGeneratedDocument(this RazorCodeDocument document, RazorLanguageKind languageKind) - => languageKind switch - { - RazorLanguageKind.CSharp => document.GetCSharpDocument(), - RazorLanguageKind.Html => document.GetHtmlDocument(), - _ => throw new System.InvalidOperationException(), - }; + => languageKind switch + { + RazorLanguageKind.CSharp => document.GetCSharpDocument(), + RazorLanguageKind.Html => document.GetHtmlDocument(), + _ => ThrowHelper.ThrowInvalidOperationException($"Unexpected language kind: {languageKind}"), + }; public static bool TryGetMinimalCSharpRange(this RazorCodeDocument codeDocument, LinePositionSpan razorRange, out LinePositionSpan csharpRange) { SourceSpan? minGeneratedSpan = null; SourceSpan? maxGeneratedSpan = null; - var sourceText = codeDocument.GetSourceText(); - var textSpan = razorRange.ToTextSpan(sourceText); + var sourceText = codeDocument.Source.Text; + var textSpan = sourceText.GetTextSpan(razorRange); var csharpDoc = codeDocument.GetCSharpDocument(); // We want to find the min and max C# source mapping that corresponds with our Razor range. @@ -121,8 +92,8 @@ public static bool TryGetMinimalCSharpRange(this RazorCodeDocument codeDocument, if (minGeneratedSpan is not null && maxGeneratedSpan is not null) { var csharpSourceText = codeDocument.GetCSharpSourceText(); - var startRange = minGeneratedSpan.Value.ToLinePositionSpan(csharpSourceText); - var endRange = maxGeneratedSpan.Value.ToLinePositionSpan(csharpSourceText); + var startRange = csharpSourceText.GetLinePositionSpan(minGeneratedSpan.Value); + var endRange = csharpSourceText.GetLinePositionSpan(maxGeneratedSpan.Value); csharpRange = new LinePositionSpan(startRange.Start, endRange.End); Debug.Assert(csharpRange.Start.CompareTo(csharpRange.End) <= 0, "Range.Start should not be larger than Range.End"); @@ -139,7 +110,7 @@ public static bool ComponentNamespaceMatches(this RazorCodeDocument razorCodeDoc var namespaceNode = (NamespaceDeclarationIntermediateNode)razorCodeDocument .GetDocumentIntermediateNode() .FindDescendantNodes() - .First(n => n is NamespaceDeclarationIntermediateNode); + .First(static n => n is NamespaceDeclarationIntermediateNode); return namespaceNode.Content == fullyQualifiedNamespace; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxNodeExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxNodeExtensions.cs index 86fb7ba42df..e3232c19d44 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxNodeExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxNodeExtensions.cs @@ -1,39 +1,30 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -using Microsoft.AspNetCore.Razor.Language.Syntax; -using Range = VisualStudio.LanguageServer.Protocol.Range; +namespace Microsoft.AspNetCore.Razor.Language.Syntax; internal static class RazorSyntaxNodeExtensions { - internal static bool IsUsingDirective(this SyntaxNode node, [NotNullWhen(true)] out SyntaxList? children) + internal static bool IsUsingDirective(this SyntaxNode node, out SyntaxList children) { // Using directives are weird, because the directive keyword ("using") is part of the C# statement it represents - if (node is RazorDirectiveSyntax razorDirective && - razorDirective.DirectiveDescriptor is null && - razorDirective.Body is RazorDirectiveBodySyntax body && - body.Keyword is CSharpStatementLiteralSyntax literal && - literal.LiteralTokens.Count > 0) + if (node is RazorDirectiveSyntax { DirectiveDescriptor: null, Body: RazorDirectiveBodySyntax body } && + body.Keyword is CSharpStatementLiteralSyntax { LiteralTokens: { Count: > 0 } literalTokens }) { - if (literal.LiteralTokens[0] is { Kind: SyntaxKind.Keyword, Content: "using" }) + if (literalTokens[0] is { Kind: SyntaxKind.Keyword, Content: "using" }) { - children = literal.LiteralTokens; + children = literalTokens; return true; } } - children = null; + children = default; return false; } @@ -62,207 +53,64 @@ body.Keyword is CSharpStatementLiteralSyntax literal && return lastNode; } - internal static bool TryGetPreviousSibling(this SyntaxNode syntaxNode, [NotNullWhen(true)] out SyntaxNode? previousSibling) + internal static bool TryGetPreviousSibling(this SyntaxNode node, [NotNullWhen(true)] out SyntaxNode? previousSibling) { - var syntaxNodeParent = syntaxNode.Parent; - if (syntaxNodeParent is null) + previousSibling = null; + + var parent = node.Parent; + if (parent is null) { - previousSibling = default; return false; } - var nodes = syntaxNodeParent.ChildNodes(); - for (var i = 0; i < nodes.Count; i++) + foreach (var child in parent.ChildNodes()) { - if (nodes[i] == syntaxNode) + if (ReferenceEquals(child, node)) { - if (i == 0) - { - previousSibling = default; - return false; - } - else - { - previousSibling = nodes[i - 1]; - return true; - } + return previousSibling is not null; } + + previousSibling = child; } - previousSibling = default; + Debug.Fail("How can we iterate node.Parent.ChildNodes() and not find node again?"); + + previousSibling = null; return false; } public static bool ContainsOnlyWhitespace(this SyntaxNode node, bool includingNewLines = true) { - if (node is null) - { - throw new ArgumentNullException(nameof(node)); - } - - var tokens = node.GetTokens(); - - for (var i = 0; i < tokens.Count; i++) + foreach (var token in node.GetTokens()) { - var tokenKind = tokens[i].Kind; - if (tokenKind != SyntaxKind.Whitespace && (tokenKind != SyntaxKind.NewLine || !includingNewLines)) + var tokenKind = token.Kind; + if (tokenKind != SyntaxKind.Whitespace && (!includingNewLines || tokenKind != SyntaxKind.NewLine)) { return false; } } - // All tokens were either whitespace or newlines. + // All tokens were either whitespace or new-lines. return true; } - public static LinePositionSpan GetLinePositionSpan(this SyntaxNode node, RazorSourceDocument source) + public static LinePositionSpan GetLinePositionSpan(this SyntaxNode node, RazorSourceDocument sourceDocument) { - if (node is null) - { - throw new ArgumentNullException(nameof(node)); - } - - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - var start = node.Position; var end = node.EndPosition; - var sourceText = source.Text; + var sourceText = sourceDocument.Text; Debug.Assert(start <= sourceText.Length && end <= sourceText.Length, "Node position exceeds source length."); if (start == sourceText.Length && node.FullWidth == 0) { // Marker symbol at the end of the document. - var location = node.GetSourceLocation(source); - var position = GetLinePosition(location); - return new LinePositionSpan(position, position); - } - - var startPosition = sourceText.Lines.GetLinePosition(start); - var endPosition = sourceText.Lines.GetLinePosition(end); - - return new LinePositionSpan(startPosition, endPosition); - - static LinePosition GetLinePosition(SourceLocation location) - { - return new LinePosition(location.LineIndex, location.CharacterIndex); - } - } - - public static Range GetRange(this SyntaxNode node, RazorSourceDocument source) - { - if (node is null) - { - throw new ArgumentNullException(nameof(node)); - } + var location = node.GetSourceLocation(sourceDocument); - if (source is null) - { - throw new ArgumentNullException(nameof(source)); + return location.ToLinePosition().ToZeroWidthSpan(); } - var lineSpan = node.GetLinePositionSpan(source); - var range = new Range - { - Start = new Position(lineSpan.Start.Line, lineSpan.Start.Character), - End = new Position(lineSpan.End.Line, lineSpan.End.Character) - }; - - return range; - } - - public static Range? GetRangeWithoutWhitespace(this SyntaxNode node, RazorSourceDocument source) - { - if (node is null) - { - throw new ArgumentNullException(nameof(node)); - } - - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - var tokens = node.GetTokens(); - - SyntaxToken? firstToken = null; - for (var i = 0; i < tokens.Count; i++) - { - var token = tokens[i]; - if (!token.IsWhitespace()) - { - firstToken = token; - break; - } - } - - SyntaxToken? lastToken = null; - for (var i = tokens.Count - 1; i >= 0; i--) - { - var token = tokens[i]; - if (!token.IsWhitespace()) - { - lastToken = token; - break; - } - } - - if (firstToken is null && lastToken is null) - { - return null; - } - - var startPositionSpan = GetLinePositionSpan(firstToken, source, node.SpanStart); - var endPositionSpan = GetLinePositionSpan(lastToken, source, node.SpanStart); - - var range = new Range - { - Start = new Position(startPositionSpan.Start.Line, startPositionSpan.Start.Character), - End = new Position(endPositionSpan.End.Line, endPositionSpan.End.Character) - }; - - return range; - - // This is needed because SyntaxToken positions taken from GetTokens - // are relative to their parent node and not to the document. - static LinePositionSpan GetLinePositionSpan(SyntaxNode? node, RazorSourceDocument source, int parentStart) - { - if (node is null) - { - throw new ArgumentNullException(nameof(node)); - } - - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - var sourceText = source.Text; - - var start = node.Position + parentStart; - var end = node.EndPosition + parentStart; - - if (start == sourceText.Length && node.FullWidth == 0) - { - // Marker symbol at the end of the document. - var location = node.GetSourceLocation(source); - var position = GetLinePosition(location); - return new LinePositionSpan(position, position); - } - - var startPosition = sourceText.Lines.GetLinePosition(start); - var endPosition = sourceText.Lines.GetLinePosition(end); - - return new LinePositionSpan(startPosition, endPosition); - - static LinePosition GetLinePosition(SourceLocation location) - { - return new LinePosition(location.LineIndex, location.CharacterIndex); - } - } + return sourceText.GetLinePositionSpan(start, end); } /// @@ -312,12 +160,12 @@ static LinePosition GetLinePosition(SourceLocation location) { if (!@this.FullSpan.Contains(span)) { - throw new ArgumentOutOfRangeException(nameof(span)); + return ThrowHelper.ThrowArgumentOutOfRangeException(nameof(span)); } var node = @this.FindToken(span.Start, includeWhitespace) - .Parent - !.FirstAncestorOrSelf(a => a.FullSpan.Contains(span)); + .Parent! + .FirstAncestorOrSelf(a => a.FullSpan.Contains(span)); node.AssumeNotNull(); @@ -356,6 +204,8 @@ static LinePosition GetLinePosition(SourceLocation location) public static bool ExistsOnTarget(this SyntaxNode node, SyntaxNode target) { + // TODO: This looks like a potential allocation hotspot and performance bottleneck. + var nodeString = node.RemoveEmptyNewLines().ToFullString(); var matchingNode = target.DescendantNodesAndSelf() // Empty new lines can affect our comparison so we remove them since they're insignificant. @@ -369,10 +219,8 @@ public static SyntaxNode RemoveEmptyNewLines(this SyntaxNode node) { if (node is MarkupTextLiteralSyntax markupTextLiteral) { - var literalTokensWithoutLines = new AspNetCore.Razor.Language.Syntax.SyntaxList( - markupTextLiteral.LiteralTokens.Where(t => t.Kind != SyntaxKind.NewLine)); - var updatedLiteral = markupTextLiteral.WithLiteralTokens(literalTokensWithoutLines); - return updatedLiteral; + var literalTokensWithoutLines = markupTextLiteral.LiteralTokens.Where(static t => t.Kind != SyntaxKind.NewLine); + return markupTextLiteral.WithLiteralTokens(literalTokensWithoutLines); } return node; @@ -383,30 +231,30 @@ public static bool IsCSharpNode(this SyntaxNode node, [NotNullWhen(true)] out CS csharpCodeBlock = null; // Any piece of C# code can potentially be surrounded by a CSharpCodeBlockSyntax. - if (node is CSharpCodeBlockSyntax outerCSharpCodeBlock) + switch (node) { - var innerCSharpNode = outerCSharpCodeBlock.ChildNodes().FirstOrDefault( - n => n is CSharpStatementSyntax or - RazorDirectiveSyntax or - CSharpExplicitExpressionSyntax or - CSharpImplicitExpressionSyntax); - if (innerCSharpNode is not null) - { - return innerCSharpNode.IsCSharpNode(out csharpCodeBlock); - } - } - // @code { - // var foo = "bar"; - // } - else if (node is RazorDirectiveSyntax razorDirective) - { - // code { + case CSharpCodeBlockSyntax outerCSharpCodeBlock: + var innerCSharpNode = outerCSharpCodeBlock.ChildNodes().FirstOrDefault( + static n => n is CSharpStatementSyntax or + RazorDirectiveSyntax or + CSharpExplicitExpressionSyntax or + CSharpImplicitExpressionSyntax); + + if (innerCSharpNode is not null) + { + return innerCSharpNode.IsCSharpNode(out csharpCodeBlock); + } + + break; + + // @code { // var foo = "bar"; // } - var razorDirectiveBody = razorDirective.Body as RazorDirectiveBodySyntax; - if (razorDirectiveBody is not null) - { - var directive = razorDirectiveBody.Keyword.ToFullString(); + case RazorDirectiveSyntax { Body: RazorDirectiveBodySyntax body }: + // code { + // var foo = "bar"; + // } + var directive = body.Keyword.ToFullString(); if (directive != "code") { return false; @@ -415,51 +263,49 @@ CSharpExplicitExpressionSyntax or // { // var foo = "bar"; // } - csharpCodeBlock = razorDirectiveBody.CSharpCode; + csharpCodeBlock = body.CSharpCode; // var foo = "bar"; - var innerCodeBlock = csharpCodeBlock.ChildNodes().FirstOrDefault(n => n is CSharpCodeBlockSyntax); + var innerCodeBlock = csharpCodeBlock.ChildNodes().FirstOrDefault(IsCSharpCodeBlockSyntax); if (innerCodeBlock is not null) { csharpCodeBlock = innerCodeBlock as CSharpCodeBlockSyntax; } - } - } - // @(x) - else if (node is CSharpExplicitExpressionSyntax csharpExplicitExpression) - { + + break; + + // @(x) // (x) - var body = csharpExplicitExpression.Body as CSharpExplicitExpressionBodySyntax; - if (body is not null) - { + case CSharpExplicitExpressionSyntax { Body: CSharpExplicitExpressionBodySyntax body }: // x csharpCodeBlock = body.CSharpCode; - } - } - // @x - else if (node is CSharpImplicitExpressionSyntax csharpImplicitExpression) - { - var csharpImplicitExpressionBody = csharpImplicitExpression.Body as CSharpImplicitExpressionBodySyntax; - if (csharpImplicitExpressionBody is not null) - { + break; + + // @x + case CSharpImplicitExpressionSyntax { Body: CSharpImplicitExpressionBodySyntax body }: // x - csharpCodeBlock = csharpImplicitExpressionBody.CSharpCode; - } - } - // @{ - // var x = 1; - // } - else if (node is CSharpStatementSyntax csharpStatement) - { - // { + csharpCodeBlock = body.CSharpCode; + break; + + // @{ // var x = 1; // } - var csharpStatementBody = csharpStatement.Body; + case CSharpStatementSyntax csharpStatement: + // { + // var x = 1; + // } + var csharpStatementBody = csharpStatement.Body; - // var x = 1; - csharpCodeBlock = csharpStatementBody.ChildNodes().FirstOrDefault(n => n is CSharpCodeBlockSyntax) as CSharpCodeBlockSyntax; + // var x = 1; + csharpCodeBlock = csharpStatementBody.ChildNodes().FirstOrDefault(IsCSharpCodeBlockSyntax) as CSharpCodeBlockSyntax; + break; } return csharpCodeBlock is not null; + + static bool IsCSharpCodeBlockSyntax(SyntaxNode node) + { + return node is CSharpCodeBlockSyntax; + } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTokenExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTokenExtensions.cs index 812313dbf6e..79f6a54c98c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTokenExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTokenExtensions.cs @@ -1,28 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; - -using Microsoft.AspNetCore.Razor.Language; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -using Microsoft.AspNetCore.Razor.Language.Syntax; +namespace Microsoft.AspNetCore.Razor.Language.Syntax; internal static class RazorSyntaxTokenExtensions { public static bool IsWhitespace(this SyntaxToken token) - { - return token.Kind == SyntaxKind.Whitespace || token.Kind == SyntaxKind.NewLine; - } + => token.Kind is SyntaxKind.Whitespace or SyntaxKind.NewLine; public static bool IsSpace(this SyntaxToken token) - { - return token.Kind == SyntaxKind.Whitespace && token.Content.Equals(" ", StringComparison.Ordinal); - } + => token.Kind == SyntaxKind.Whitespace && token.Content == " "; public static bool IsTab(this SyntaxToken token) - { - return token.Kind == SyntaxKind.Whitespace && token.Content.Equals("\t", StringComparison.Ordinal); - } + => token.Kind == SyntaxKind.Whitespace && token.Content == "\t"; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTreeExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTreeExtensions.cs index 86662f4e4de..251bb5f4c5b 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTreeExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RazorSyntaxTreeExtensions.cs @@ -2,59 +2,38 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.AspNetCore.Razor.PooledObjects; + +namespace Microsoft.AspNetCore.Razor.Language; internal static class RazorSyntaxTreeExtensions { public static ImmutableArray GetSectionDirectives(this RazorSyntaxTree syntaxTree) - { - return GetDirectives(syntaxTree, directive => directive.DirectiveDescriptor?.Directive == SectionDirective.Directive.Directive); - } + => GetDirectives(syntaxTree, static d => d.DirectiveDescriptor?.Directive == SectionDirective.Directive.Directive); public static ImmutableArray GetCodeBlockDirectives(this RazorSyntaxTree syntaxTree) - { - return GetDirectives(syntaxTree, directive => directive.DirectiveDescriptor?.Kind == DirectiveKind.CodeBlock); - } + => GetDirectives(syntaxTree, static d => d.DirectiveDescriptor?.Kind == DirectiveKind.CodeBlock); private static ImmutableArray GetDirectives(RazorSyntaxTree syntaxTree, Func predicate) { - return syntaxTree.Root - .DescendantNodes(node => node is RazorDocumentSyntax or MarkupBlockSyntax or CSharpCodeBlockSyntax) - .OfType() - .Where(predicate) - .SelectAsArray(d => d); - } + using var builder = new PooledArrayBuilder(); - public static IReadOnlyList GetCSharpStatements(this RazorSyntaxTree syntaxTree) - { - // We want all nodes that represent Razor C# statements, @{ ... }. - var statements = syntaxTree.Root.DescendantNodes().OfType().ToList(); - return statements; - } - - public static SyntaxNode? FindInnermostNode( - this RazorSyntaxTree syntaxTree, - SourceText sourceText, - Position position, - ILogger logger, - bool includeWhitespace = false) - { - if (!position.TryGetAbsoluteIndex(sourceText, logger, out var absoluteIndex)) + foreach (var node in syntaxTree.Root.DescendantNodes(ShouldDescendIntoChildren)) { - return default; + if (node is RazorDirectiveSyntax directive && predicate(directive)) + { + builder.Add(directive); + } } - return syntaxTree.Root.FindInnermostNode(absoluteIndex, includeWhitespace); + return builder.ToImmutable(); + + static bool ShouldDescendIntoChildren(SyntaxNode node) + { + return node is RazorDocumentSyntax or MarkupBlockSyntax or CSharpCodeBlockSyntax; + } } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_LinePosition.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_LinePosition.cs new file mode 100644 index 00000000000..7401bd5ca1f --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_LinePosition.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.LanguageServer.Protocol; + +internal static partial class RoslynLspExtensions +{ + public static Position ToPosition(this LinePosition linePosition) + => RoslynLspFactory.CreatePosition(linePosition.Line, linePosition.Character); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_LinePositionSpan.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_LinePositionSpan.cs new file mode 100644 index 00000000000..2819933b95f --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_LinePositionSpan.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.LanguageServer.Protocol; + +internal static partial class RoslynLspExtensions +{ + public static Range ToRange(this LinePositionSpan linePositionSpan) + => RoslynLspFactory.CreateRange(linePositionSpan); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_Position.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_Position.cs new file mode 100644 index 00000000000..e4cd3c1ac93 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_Position.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.LanguageServer.Protocol; + +internal static partial class RoslynLspExtensions +{ + public static LinePosition ToLinePosition(this Position position) + => new(position.Line, position.Character); + + public static string ToDisplayString(this Position position) + => $"({position.Line}, {position.Character})"; +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_Range.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_Range.cs new file mode 100644 index 00000000000..af7e54346c8 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspExtensions_Range.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.LanguageServer.Protocol; + +internal static partial class RoslynLspExtensions +{ + public static LinePositionSpan ToLinePositionSpan(this Range range) + => new(range.Start.ToLinePosition(), range.End.ToLinePosition()); + + public static string ToDisplayString(this Range range) + => $"{range.Start.ToDisplayString()}-{range.End.ToDisplayString()}"; +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspFactory.cs new file mode 100644 index 00000000000..841ea8c1ed4 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/RoslynLspFactory.cs @@ -0,0 +1,191 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Diagnostics; +using Microsoft.CodeAnalysis.Text; + +namespace Roslyn.LanguageServer.Protocol; + +internal static class RoslynLspFactory +{ + private static readonly Position s_defaultPosition = new(0, 0); + + private static readonly Range s_defaultRange = new() + { + Start = s_defaultPosition, + End = s_defaultPosition + }; + + private static readonly Position s_undefinedPosition = new(-1, -1); + + private static readonly Range s_undefinedRange = new() + { + Start = s_undefinedPosition, + End = s_undefinedPosition + }; + + /// + /// Returns a for line 0 and character 0. + /// + public static Position DefaultPosition + { + get + { + var defaultPosition = s_defaultPosition; + + // Since Position is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + defaultPosition.Line == 0 && + defaultPosition.Character == 0, + $"{nameof(RoslynLspFactory)}.{nameof(DefaultPosition)} has been corrupted. Current value: {defaultPosition.ToDisplayString()}"); + + return defaultPosition; + } + } + + /// + /// Returns a for starting line 0 and character 0, + /// and ending line 0 and character 0. + /// + public static Range DefaultRange + { + get + { + var defaultRange = s_defaultRange; + + // Since Range is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + defaultRange.Start.Line == 0 && + defaultRange.Start.Character == 0 && + defaultRange.End.Line == 0 && + defaultRange.End.Character == 0, + $"{nameof(RoslynLspFactory)}.{nameof(DefaultRange)} has been corrupted. Current value: {defaultRange.ToDisplayString()}"); + + return defaultRange; + } + } + + public static Position UndefinedPosition + { + get + { + var undefinedPosition = s_undefinedPosition; + + // Since Position is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + undefinedPosition.Line == -1 && + undefinedPosition.Character == -1, + $"{nameof(RoslynLspFactory)}.{nameof(UndefinedPosition)} has been corrupted. Current value: {undefinedPosition.ToDisplayString()}"); + + return undefinedPosition; + } + } + + public static Range UndefinedRange + { + get + { + var undefinedRange = s_undefinedRange; + + // Since Range is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + undefinedRange.Start.Line == -1 && + undefinedRange.Start.Character == -1 && + undefinedRange.End.Line == -1 && + undefinedRange.End.Character == -1, + $"{nameof(RoslynLspFactory)}.{nameof(UndefinedRange)} has been corrupted. Current value: {undefinedRange.ToDisplayString()}"); + + return undefinedRange; + } + } + + public static Position CreatePosition(int line, int character) + => (line, character) switch + { + (0, 0) => DefaultPosition, + (-1, -1) => UndefinedPosition, + _ => new(line, character) + }; + + public static Position CreatePosition(LinePosition linePosition) + => CreatePosition(linePosition.Line, linePosition.Character); + + public static Position CreatePosition((int line, int character) position) + => CreatePosition(position.line, position.character); + + public static Range CreateRange(int startLine, int startCharacter, int endLine, int endCharacter) + => startLine == endLine && startCharacter == endCharacter + ? CreateZeroWidthRange(startLine, startCharacter) + : CreateRange(CreatePosition(startLine, startCharacter), CreatePosition(endLine, endCharacter)); + + public static Range CreateRange(Position start, Position end) + => new() { Start = start, End = end }; + + public static Range CreateRange(LinePosition start, LinePosition end) + => CreateRange(start.Line, start.Character, end.Line, end.Character); + + public static Range CreateRange((int line, int character) start, (int line, int character) end) + => CreateRange(start.line, start.character, end.line, end.character); + + public static Range CreateRange(LinePositionSpan span) + => CreateRange(span.Start, span.End); + + public static Range CreateZeroWidthRange(int line, int character) + => (line, character) switch + { + (0, 0) => DefaultRange, + (-1, -1) => UndefinedRange, + _ => CreateZeroWidthRange(CreatePosition(line, character)) + }; + + public static Range CreateZeroWidthRange(Position position) + => CreateRange(position, position); + + public static Range CreateZeroWidthRange(LinePosition position) + => CreateRange(position, position); + + public static Range CreateZeroWidthRange((int line, int character) position) + => CreateRange(position, position); + + public static Range CreateSingleLineRange(int line, int character, int length) + => CreateRange(line, character, line, character + length); + + public static Range CreateSingleLineRange(Position start, int length) + => CreateRange(start, CreatePosition(start.Line, start.Character + length)); + + public static Range CreateSingleLineRange(LinePosition start, int length) + => CreateSingleLineRange(start.Line, start.Character, length); + + public static Range CreateSingleLineRange((int line, int character) start, int length) + => CreateRange(CreatePosition(start), CreatePosition(start.line, start.character + length)); + + public static TextEdit CreateTextEdit(Range range, string newText) + => new() { Range = range, NewText = newText }; + + public static TextEdit CreateTextEdit(LinePositionSpan span, string newText) + => CreateTextEdit(CreateRange(span), newText); + + public static TextEdit CreateTextEdit(int startLine, int startCharacter, int endLine, int endCharacter, string newText) + => CreateTextEdit(CreateRange(startLine, startCharacter, endLine, endCharacter), newText); + + public static TextEdit CreateTextEdit(Position start, Position end, string newText) + => CreateTextEdit(CreateRange(start, end), newText); + + public static TextEdit CreateTextEdit(LinePosition start, LinePosition end, string newText) + => CreateTextEdit(CreateRange(start, end), newText); + + public static TextEdit CreateTextEdit((int line, int character) start, (int line, int character) end, string newText) + => CreateTextEdit(CreateRange(start, end), newText); + + public static TextEdit CreateTextEdit(int line, int character, string newText) + => CreateTextEdit(CreateZeroWidthRange(line, character), newText); + + public static TextEdit CreateTextEdit(Position position, string newText) + => CreateTextEdit(CreateZeroWidthRange(position), newText); + + public static TextEdit CreateTextEdit(LinePosition position, string newText) + => CreateTextEdit(CreateZeroWidthRange(position.Line, position.Character), newText); + + public static TextEdit CreateTextEdit((int line, int character) position, string newText) + => CreateTextEdit(CreateZeroWidthRange(position), newText); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs index 5030209aee7..8f4a278ea39 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SolutionExtensions.cs @@ -1,15 +1,15 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; +using Microsoft.AspNetCore.Razor; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis; internal static class SolutionExtensions { internal static Project GetRequiredProject(this Solution solution, ProjectId projectId) { return solution.GetProject(projectId) - ?? throw new InvalidOperationException($"The projectId {projectId} did not exist in {solution}."); + ?? ThrowHelper.ThrowInvalidOperationException($"The projectId {projectId} did not exist in {solution}."); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceLocationExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceLocationExtensions.cs new file mode 100644 index 00000000000..619f2bfb0d9 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceLocationExtensions.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Razor.Workspaces; + +internal static class SourceLocationExtensions +{ + public static LinePosition ToLinePosition(this SourceLocation location) + => new(location.LineIndex, location.CharacterIndex); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceSpanExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceSpanExtensions.cs index 6f880da91a5..1504ebe29e7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceSpanExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceSpanExtensions.cs @@ -3,27 +3,11 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.Workspaces; internal static class SourceSpanExtensions { - public static Range ToRange(this SourceSpan sourceSpan, SourceText sourceText) - { - sourceText.GetLinesAndOffsets(sourceSpan, out var startLine, out var startChar, out var endLine, out var endChar); - - return new Range - { - Start = new Position(startLine, startChar), - End = new Position(endLine, endChar), - }; - } - - public static LinePositionSpan ToLinePositionSpan(this SourceSpan sourceSpan, SourceText sourceText) - { - sourceText.GetLinesAndOffsets(sourceSpan, out var startLine, out var startChar, out var endLine, out var endChar); - - return new LinePositionSpan(new(startLine, startChar), new(endLine, endChar)); - } + public static TextSpan ToTextSpan(this SourceSpan span) + => new(span.AbsoluteIndex, span.Length); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs index a49069dfd09..6d72290f117 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SourceTextExtensions.cs @@ -2,12 +2,12 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.Diagnostics; +using System.Buffers; +using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Razor.Workspaces; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Text; internal static class SourceTextExtensions { @@ -16,16 +16,6 @@ internal static class SourceTextExtensions /// public static TextChangeRange GetEncompassingTextChangeRange(this SourceText newText, SourceText oldText) { - if (newText is null) - { - throw new ArgumentNullException(nameof(newText)); - } - - if (oldText is null) - { - throw new ArgumentNullException(nameof(oldText)); - } - var ranges = newText.GetChangeRanges(oldText); if (ranges.Count == 0) { @@ -41,82 +31,39 @@ public static TextChangeRange GetEncompassingTextChangeRange(this SourceText new return TextChangeRange.Collapse(ranges); } - public static void GetLineAndOffset(this SourceText source, int position, out int lineNumber, out int offset) - { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + public static LinePosition GetLinePosition(this SourceText text, int position) + => text.Lines.GetLinePosition(position); - var line = source.Lines.GetLineFromPosition(position); + public static LinePositionSpan GetLinePositionSpan(this SourceText text, TextSpan span) + => text.Lines.GetLinePositionSpan(span); - lineNumber = line.LineNumber; - offset = position - line.Start; - } + public static LinePositionSpan GetLinePositionSpan(this SourceText text, SourceSpan span) + => text.GetLinePositionSpan(span.ToTextSpan()); - public static void GetLinesAndOffsets( - this SourceText source, - TextSpan textSpan, - out int startLineNumber, - out int startOffset, - out int endLineNumber, - out int endOffset) - { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + public static LinePositionSpan GetLinePositionSpan(this SourceText text, int start, int end) + => text.GetLinePositionSpan(TextSpan.FromBounds(start, end)); - source.GetLineAndOffset(textSpan.Start, out startLineNumber, out startOffset); - source.GetLineAndOffset(textSpan.End, out endLineNumber, out endOffset); - } - - public static void GetLinesAndOffsets( - this SourceText source, - SourceSpan sourceSpan, - out int startLineNumber, - out int startOffset, - out int endLineNumber, - out int endOffset) - { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + public static int GetPosition(this SourceText text, LinePosition position) + => text.Lines.GetPosition(position); - source.GetLineAndOffset(sourceSpan.AbsoluteIndex, out startLineNumber, out startOffset); - source.GetLineAndOffset(sourceSpan.AbsoluteIndex + sourceSpan.Length, out endLineNumber, out endOffset); - } + public static int GetPosition(this SourceText text, int line, int character) + => text.GetPosition(new LinePosition(line, character)); - public static string GetSubTextString(this SourceText source, TextSpan span) + public static string GetSubTextString(this SourceText text, TextSpan span) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + using var _ = ArrayPool.Shared.GetPooledArray(span.Length, out var charBuffer); - var charBuffer = new char[span.Length]; - source.CopyTo(span.Start, charBuffer, 0, span.Length); - return new string(charBuffer); + text.CopyTo(span.Start, charBuffer, 0, span.Length); + return new string(charBuffer, 0, span.Length); } - public static bool NonWhitespaceContentEquals(this SourceText source, SourceText other) + public static bool NonWhitespaceContentEquals(this SourceText text, SourceText other) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - if (other is null) - { - throw new ArgumentNullException(nameof(other)); - } - var i = 0; var j = 0; - while (i < source.Length && j < other.Length) + while (i < text.Length && j < other.Length) { - if (char.IsWhiteSpace(source[i])) + if (char.IsWhiteSpace(text[i])) { i++; continue; @@ -126,7 +73,7 @@ public static bool NonWhitespaceContentEquals(this SourceText source, SourceText j++; continue; } - else if (source[i] != other[j]) + else if (text[i] != other[j]) { return false; } @@ -135,7 +82,7 @@ public static bool NonWhitespaceContentEquals(this SourceText source, SourceText j++; } - while (i < source.Length && char.IsWhiteSpace(source[i])) + while (i < text.Length && char.IsWhiteSpace(text[i])) { i++; } @@ -145,149 +92,181 @@ public static bool NonWhitespaceContentEquals(this SourceText source, SourceText j++; } - return i == source.Length && j == other.Length; + return i == text.Length && j == other.Length; } - public static int? GetFirstNonWhitespaceOffset(this SourceText source, TextSpan? span, out int newLineCount) + public static bool TryGetFirstNonWhitespaceOffset(this SourceText text, out int offset) + => text.TryGetFirstNonWhitespaceOffset(new TextSpan(0, text.Length), out offset); + + public static bool TryGetFirstNonWhitespaceOffset(this SourceText text, TextSpan span, out int offset) { - if (source is null) + for (var i = span.Start; i < span.End; i++) { - throw new ArgumentNullException(nameof(source)); + if (!char.IsWhiteSpace(text[i])) + { + offset = i - span.Start; + return true; + } } - span ??= new TextSpan(0, source.Length); + offset = -1; + return false; + } + + public static bool TryGetFirstNonWhitespaceOffset(this SourceText text, TextSpan span, out int offset, out int newLineCount) + { newLineCount = 0; - for (var i = span.Value.Start; i < span.Value.End; i++) + for (var i = span.Start; i < span.End; i++) { - if (!char.IsWhiteSpace(source[i])) + if (!char.IsWhiteSpace(text[i])) { - return i - span.Value.Start; + offset = i - span.Start; + return true; } - else if (source[i] == '\n') + else if (text[i] == '\n') { newLineCount++; } } - return null; + offset = -1; + newLineCount = -1; + return false; } - // Given the source text and the current span, we start at the ending span location and iterate towards the start - // until we've reached a non-whitespace character. - // For instance " abcdef " would have a last non-whitespace offset of 7 to correspond to the charcter 'f'. - public static int? GetLastNonWhitespaceOffset(this SourceText source, TextSpan? span, out int newLineCount) + /// + /// + /// Given the source text and the current span, we start at the ending span location and iterate towards the start + /// until we've reached a non-whitespace character. + /// + /// + /// For instance, " abcdef " would have a last non-whitespace offset of 7 to correspond to the character 'f'. + /// + /// + public static bool TryGetLastNonWhitespaceOffset(this SourceText text, TextSpan span, out int offset) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - span ??= new TextSpan(0, source.Length); - newLineCount = 0; + // If the span is at the end of the document, it's common for the "End" to represent 1 past the end of the source + var indexableSpanEnd = Math.Min(span.End, text.Length - 1); - // If the span is at the end of the document it's common for the "End" to represent 1 past the end of the source - var indexableSpanEnd = Math.Min(span.Value.End, source.Length - 1); - - for (var i = indexableSpanEnd; i >= span.Value.Start; i--) + for (var i = indexableSpanEnd; i >= span.Start; i--) { - if (!char.IsWhiteSpace(source[i])) - { - return i - span.Value.Start; - } - else if (source[i] == '\n') + if (!char.IsWhiteSpace(text[i])) { - newLineCount++; + offset = i - span.Start; + return true; } } - return null; + offset = -1; + return false; } - public static bool TryGetAbsoluteIndex(this SourceText sourceText, int line, int character, out int absoluteIndex) - { - return sourceText.TryGetAbsoluteIndex(line, character, logger: null, out absoluteIndex); - } + public static bool IsValidPosition(this SourceText text, LinePosition lspPosition) + => text.TryGetAbsoluteIndex(lspPosition, out _); + + public static bool IsValidPosition(this SourceText text, (int line, int character) lspPosition) + => text.TryGetAbsoluteIndex(lspPosition, out _); + + public static bool IsValidPosition(this SourceText text, int line, int character) + => text.TryGetAbsoluteIndex(line, character, out _); - public static bool TryGetAbsoluteIndex(this SourceText sourceText, int line, int character, ILogger? logger, out int absoluteIndex) + public static bool TryGetAbsoluteIndex(this SourceText text, LinePosition position, out int absoluteIndex) + => text.TryGetAbsoluteIndex(position.Line, position.Character, out absoluteIndex); + + public static bool TryGetAbsoluteIndex(this SourceText text, (int line, int character) position, out int absoluteIndex) + => text.TryGetAbsoluteIndex(position.line, position.character, out absoluteIndex); + + public static bool TryGetAbsoluteIndex(this SourceText text, int line, int character, out int absoluteIndex) { absoluteIndex = 0; - var lineCount = sourceText.Lines.Count; - if (line > lineCount || - (line == lineCount && character > 0)) - { - if (logger != null) - { - logger?.Log(LogLevel.Error, SR.FormatPositionLine_Outside_Range(line, nameof(sourceText), sourceText.Lines.Count), exception: null); - Debug.Fail(SR.FormatPositionLine_Outside_Range(line, nameof(sourceText), sourceText.Lines.Count)); - } + if (character < 0) + { return false; } - // LSP spec allowed a Range to end one line past the end, and character 0. SourceText does not, so we adjust to the final char position - if (line == lineCount) + var lineCount = text.Lines.Count; + + if (line > lineCount) { - absoluteIndex = sourceText.Length; + return false; } - else + + // The LSP spec allows the end of a range to be after the last line at character 0. + // SourceText doesn't allow that, so we adjust to SourceText.Length. + if (line == lineCount) { - var sourceLine = sourceText.Lines[line]; - var lineLengthIncludingLineBreak = sourceLine.SpanIncludingLineBreak.Length; - if (character > lineLengthIncludingLineBreak) + if (character == 0) { - if (logger != null) - { - var errorMessage = SR.FormatPositionCharacter_Outside_Range(character, nameof(sourceText), lineLengthIncludingLineBreak); - logger?.Log(LogLevel.Error, errorMessage, exception: null); - Debug.Fail(errorMessage); - } - - return false; + absoluteIndex = text.Length; + return true; } - absoluteIndex = sourceLine.Start + character; + return false; } - return true; - } + var textLine = text.Lines[line]; - public static int GetRequiredAbsoluteIndex(this SourceText sourceText, int line, int character, ILogger? logger = null) - { - if (!sourceText.TryGetAbsoluteIndex(line, character, logger, out var absolutePosition)) + if (character > textLine.SpanIncludingLineBreak.Length) { - throw new ArgumentOutOfRangeException($"({line},{character}) matches or exceeds SourceText boundary {sourceText.Lines.Count}."); + return false; } - return absolutePosition; + absoluteIndex = textLine.Start + character; + return true; } - public static TextSpan GetTextSpan(this SourceText sourceText, int startLine, int startCharacter, int endLine, int endCharacter) - { - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } + public static int GetRequiredAbsoluteIndex(this SourceText text, LinePosition position) + => text.GetRequiredAbsoluteIndex(position.Line, position.Character); + + public static int GetRequiredAbsoluteIndex(this SourceText text, (int line, int character) position) + => text.GetRequiredAbsoluteIndex(position.line, position.character); + + public static int GetRequiredAbsoluteIndex(this SourceText text, int line, int character) + => text.TryGetAbsoluteIndex(line, character, out var absolutionPosition) + ? absolutionPosition + : ThrowHelper.ThrowInvalidOperationException($"({line},{character}) matches or exceeds SourceText boundary {text.Lines.Count}."); + + public static TextSpan GetTextSpan(this SourceText text, LinePosition start, LinePosition end) + => text.GetTextSpan(start.Line, start.Character, end.Line, end.Character); - var start = GetAbsoluteIndex(startLine, startCharacter, sourceText, "Start"); - var end = GetAbsoluteIndex(endLine, endCharacter, sourceText, "End"); + public static TextSpan GetTextSpan(this SourceText text, LinePositionSpan span) + => text.GetTextSpan(span.Start, span.End); + + public static TextSpan GetTextSpan(this SourceText text, int startLine, int startCharacter, int endLine, int endCharacter) + { + var start = GetAbsoluteIndex(text, startLine, startCharacter, "Start"); + var end = GetAbsoluteIndex(text, endLine, endCharacter, "End"); var length = end - start; if (length < 0) { - throw new ArgumentOutOfRangeException($"({startLine},{startCharacter})-({endLine},{endCharacter}) resolved to zero or negative length."); + return ThrowHelper.ThrowInvalidOperationException($"({startLine},{startCharacter})-({endLine},{endCharacter}) resolved to zero or negative length."); } return new TextSpan(start, length); - static int GetAbsoluteIndex(int line, int character, SourceText sourceText, string argName) + static int GetAbsoluteIndex(SourceText text, int line, int character, string name) { - if (!sourceText.TryGetAbsoluteIndex(line, character, out var absolutePosition)) - { - throw new ArgumentOutOfRangeException($"{argName} ({line},{character}) matches or exceeds SourceText boundary {sourceText.Lines.Count}."); - } + return text.TryGetAbsoluteIndex(line, character, out var absolutePosition) + ? absolutePosition + : ThrowHelper.ThrowInvalidOperationException($"{name}: ({line},{character}) matches or exceeds SourceText boundary {text.Lines.Count}."); + } + } + + public static bool TryGetSourceLocation(this SourceText text, LinePosition position, out SourceLocation location) + => text.TryGetSourceLocation(position.Line, position.Character, out location); - return absolutePosition; + public static bool TryGetSourceLocation(this SourceText text, int line, int character, out SourceLocation location) + { + if (text.TryGetAbsoluteIndex(line, character, out var absoluteIndex)) + { + location = new SourceLocation(absoluteIndex, line, character); + return true; } + + location = default; + return false; } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/StringExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/StringExtensions.cs index 82c5df1eaf8..1ce3a839d87 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/StringExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/StringExtensions.cs @@ -1,19 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Razor; internal static class StringExtensions { public static int? GetFirstNonWhitespaceOffset(this string line) { - if (line is null) - { - throw new ArgumentNullException(nameof(line)); - } - for (var i = 0; i < line.Length; i++) { if (!char.IsWhiteSpace(line[i])) @@ -27,11 +20,6 @@ internal static class StringExtensions public static int? GetLastNonWhitespaceOffset(this string line) { - if (line is null) - { - throw new ArgumentNullException(nameof(line)); - } - for (var i = line.Length - 1; i >= 0; i--) { if (!char.IsWhiteSpace(line[i])) @@ -45,11 +33,6 @@ internal static class StringExtensions public static string GetLeadingWhitespace(this string lineText) { - if (lineText is null) - { - throw new ArgumentNullException(nameof(lineText)); - } - var firstOffset = lineText.GetFirstNonWhitespaceOffset(); return firstOffset.HasValue @@ -59,11 +42,6 @@ public static string GetLeadingWhitespace(this string lineText) public static string GetTrailingWhitespace(this string lineText) { - if (lineText is null) - { - throw new ArgumentNullException(nameof(lineText)); - } - var lastOffset = lineText.GetLastNonWhitespaceOffset(); return lastOffset.HasValue diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SyntaxListExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SyntaxListExtensions.cs index 7eed5dd1b99..c8a1dec4d18 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SyntaxListExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SyntaxListExtensions.cs @@ -1,15 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Diagnostics.CodeAnalysis; using System.Linq; -using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -// Inside namespace, to avoid ambiguity with Microsoft.CodeAnalysis.* -using Microsoft.AspNetCore.Razor.Language.Syntax; +namespace Microsoft.AspNetCore.Razor.Language.Syntax; internal static class SyntaxListExtensions { @@ -17,36 +13,24 @@ internal static SyntaxNode PreviousSiblingOrSelf(this SyntaxList syntaxNode, + -1 => ThrowHelper.ThrowInvalidOperationException("The provided node was not in the SyntaxList"), + _ => syntaxList[index - 1] + }; } internal static SyntaxNode NextSiblingOrSelf(this SyntaxList syntaxList, RazorSyntaxNode syntaxNode) { var index = syntaxList.IndexOf(syntaxNode); - if (index == syntaxList.Count - 1) - { - return syntaxNode; - } - else if (index == -1) + return index switch { - throw new ArgumentException("The provided node was not in the SyntaxList"); - } - else - { - return syntaxList[index + 1]; - } + var i when i == syntaxList.Count - 1 => syntaxNode, + -1 => ThrowHelper.ThrowInvalidOperationException("The provided node was not in the SyntaxList"), + _ => syntaxList[index + 1] + }; } internal static bool TryGetOpenBraceNode(this SyntaxList children, [NotNullWhen(true)] out RazorMetaCodeSyntax? brace) @@ -54,9 +38,10 @@ internal static bool TryGetOpenBraceNode(this SyntaxList childr // If there is no whitespace between the directive and the brace then there will only be // three children and the brace should be the first child brace = null; - if (children.FirstOrDefault(c => c.Kind == SyntaxKind.RazorMetaCode) is RazorMetaCodeSyntax metaCode) + + if (children.FirstOrDefault(static c => c.Kind == SyntaxKind.RazorMetaCode) is RazorMetaCodeSyntax metaCode) { - var token = metaCode.MetaCode.SingleOrDefault(m => m.Kind == SyntaxKind.LeftBrace); + var token = metaCode.MetaCode.SingleOrDefault(static m => m.Kind == SyntaxKind.LeftBrace); if (token != null) { brace = metaCode; @@ -65,14 +50,16 @@ internal static bool TryGetOpenBraceNode(this SyntaxList childr return brace != null; } + internal static bool TryGetCloseBraceNode(this SyntaxList children, [NotNullWhen(true)] out RazorMetaCodeSyntax? brace) { // If there is no whitespace between the directive and the brace then there will only be // three children and the brace should be the last child brace = null; - if (children.LastOrDefault(c => c.Kind == SyntaxKind.RazorMetaCode) is RazorMetaCodeSyntax metaCode) + + if (children.LastOrDefault(static c => c.Kind == SyntaxKind.RazorMetaCode) is RazorMetaCodeSyntax metaCode) { - var token = metaCode.MetaCode.SingleOrDefault(m => m.Kind == SyntaxKind.RightBrace); + var token = metaCode.MetaCode.SingleOrDefault(static m => m.Kind == SyntaxKind.RightBrace); if (token != null) { brace = metaCode; @@ -81,12 +68,14 @@ internal static bool TryGetCloseBraceNode(this SyntaxList child return brace != null; } + internal static bool TryGetOpenBraceToken(this SyntaxList children, [NotNullWhen(true)] out SyntaxToken? brace) { brace = null; + if (children.TryGetOpenBraceNode(out var metacode)) { - var token = metacode.MetaCode.SingleOrDefault(m => m.Kind == SyntaxKind.LeftBrace); + var token = metacode.MetaCode.SingleOrDefault(static m => m.Kind == SyntaxKind.LeftBrace); if (token != null) { brace = token; @@ -99,9 +88,10 @@ internal static bool TryGetOpenBraceToken(this SyntaxList child internal static bool TryGetCloseBraceToken(this SyntaxList children, [NotNullWhen(true)] out SyntaxToken? brace) { brace = null; + if (children.TryGetCloseBraceNode(out var metacode)) { - var token = metacode.MetaCode.SingleOrDefault(m => m.Kind == SyntaxKind.RightBrace); + var token = metacode.MetaCode.SingleOrDefault(static m => m.Kind == SyntaxKind.RightBrace); if (token != null) { brace = token; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TagHelperDescriptorExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TagHelperDescriptorExtensions.cs index 12f69453735..b303b2a65e4 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TagHelperDescriptorExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TagHelperDescriptorExtensions.cs @@ -9,10 +9,10 @@ namespace Microsoft.CodeAnalysis.Razor.Workspaces; internal static class TagHelperDescriptorExtensions { - public static bool IsAttributeDescriptor(this TagHelperDescriptor d) + public static bool IsAttributeDescriptor(this TagHelperDescriptor descriptor) { - return d.Metadata.TryGetValue(TagHelperMetadata.Common.ClassifyAttributesOnly, out var value) || - string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase); + return descriptor.Metadata.TryGetValue(TagHelperMetadata.Common.ClassifyAttributesOnly, out var value) || + string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase); } public static string? TryGetComponentTag(this TagHelperDescriptor descriptor) @@ -25,29 +25,29 @@ public static bool IsAttributeDescriptor(this TagHelperDescriptor d) // TODO: Add @using statements if required, or fully qualify (GetTypeName()) - using var _ = StringBuilderPool.GetPooledObject(out var sb); + using var _ = StringBuilderPool.GetPooledObject(out var builder); - sb.Append('<'); - sb.Append(typeName); + builder.Append('<'); + builder.Append(typeName); foreach (var requiredAttribute in descriptor.EditorRequiredAttributes) { - sb.Append(' '); - sb.Append(requiredAttribute.Name); - sb.Append("=\"\""); + builder.Append(' '); + builder.Append(requiredAttribute.Name); + builder.Append("=\"\""); } if (descriptor.AllowedChildTags.Length > 0) { - sb.Append(">'); + builder.Append(">'); } else { - sb.Append(" />"); + builder.Append(" />"); } - return sb.ToString(); + return builder.ToString(); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextChangeExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextChangeExtensions.cs deleted file mode 100644 index e0479829ef1..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextChangeExtensions.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System; -using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -internal static class TextChangeExtensions -{ - public static TextEdit ToTextEdit(this TextChange textChange, SourceText sourceText) - { - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } - - var range = textChange.Span.ToRange(sourceText); - - Assumes.NotNull(textChange.NewText); - - return new TextEdit() - { - NewText = textChange.NewText, - Range = range - }; - } - - public static RazorTextChange ToRazorTextChange(this TextChange textChange) - { - return new RazorTextChange() - { - Span = new RazorTextSpan() - { - Start = textChange.Span.Start, - Length = textChange.Span.Length, - }, - NewText = textChange.NewText - }; - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextEditExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextEditExtensions.cs deleted file mode 100644 index f1118282aa0..00000000000 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextEditExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT license. See License.txt in the project root for license information. - -using System; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -internal static class TextEditExtensions -{ - public static TextChange ToTextChange(this TextEdit textEdit, SourceText sourceText) - { - if (textEdit is null) - { - throw new ArgumentNullException(nameof(textEdit)); - } - - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } - - var span = textEdit.Range.ToTextSpan(sourceText); - return new TextChange(span, textEdit.NewText); - } -} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextLineExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextLineExtensions.cs index a0a082ed7d4..6a13e4608f1 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextLineExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextLineExtensions.cs @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; -using Microsoft.CodeAnalysis.Text; +using Microsoft.AspNetCore.Razor; +using Microsoft.CodeAnalysis.Razor; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Text; internal static class TextLineExtensions { @@ -15,9 +15,7 @@ public static string GetLeadingWhitespace(this TextLine line) public static int GetIndentationSize(this TextLine line, long tabSize) { - var text = line.Text; - - Assumes.NotNull(text); + var text = line.Text.AssumeNotNull(); var indentation = 0; for (var i = line.Start; i < line.End; i++) @@ -53,9 +51,11 @@ public static int GetIndentationSize(this TextLine line, long tabSize) { if (startOffset > line.SpanIncludingLineBreak.Length) { - throw new ArgumentOutOfRangeException(nameof(startOffset), SR.Invalid_Offset); + return ThrowHelper.ThrowArgumentOutOfRangeException(nameof(startOffset), SR.Invalid_Offset); } - return line.Text!.GetFirstNonWhitespaceOffset(TextSpan.FromBounds(line.Start + startOffset, line.EndIncludingLineBreak), out _); + return line.Text!.TryGetFirstNonWhitespaceOffset(TextSpan.FromBounds(line.Start + startOffset, line.EndIncludingLineBreak), out var offset) + ? offset + : null; } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextSpanExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextSpanExtensions.cs index 8f5bb6e5d5e..fdf79c6bc7c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextSpanExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextSpanExtensions.cs @@ -1,22 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; - -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Text; internal static class TextSpanExtensions { internal static TextSpan TrimLeadingWhitespace(this TextSpan span, SourceText text) { - if (text is null) - { - throw new ArgumentNullException(nameof(text)); - } - for (var i = 0; i < span.Length; ++i) { if (!char.IsWhiteSpace(text[span.Start + i])) @@ -27,22 +17,4 @@ internal static TextSpan TrimLeadingWhitespace(this TextSpan span, SourceText te return span; } - - public static Range ToRange(this TextSpan span, SourceText sourceText) - { - if (sourceText is null) - { - throw new ArgumentNullException(nameof(sourceText)); - } - - sourceText.GetLinesAndOffsets(span, out var startLine, out var startChar, out var endLine, out var endChar); - - var range = new Range - { - Start = new Position(startLine, startChar), - End = new Position(endLine, endChar) - }; - - return range; - } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_LinePosition.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_LinePosition.cs new file mode 100644 index 00000000000..8beb8510be0 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_LinePosition.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static Position ToPosition(this LinePosition linePosition) + => VsLspFactory.CreatePosition(linePosition.Line, linePosition.Character); + + public static Range ToZeroWidthRange(this LinePosition position) + => VsLspFactory.CreateZeroWidthRange(position); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_LinePositionSpan.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_LinePositionSpan.cs new file mode 100644 index 00000000000..270532bb5ab --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_LinePositionSpan.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static Range ToRange(this LinePositionSpan linePositionSpan) + => VsLspFactory.CreateRange(linePositionSpan); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_Position.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_Position.cs new file mode 100644 index 00000000000..df93c93333f --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_Position.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static void Deconstruct(this Position position, out int line, out int character) + => (line, character) = (position.Line, position.Character); + + public static LinePosition ToLinePosition(this Position position) + => new(position.Line, position.Character); + + public static Range ToZeroWidthRange(this Position position) + => VsLspFactory.CreateZeroWidthRange(position); + + public static int CompareTo(this Position position, Position other) + { + var result = position.Line.CompareTo(other.Line); + return result != 0 ? result : position.Character.CompareTo(other.Character); + } + + public static string ToDisplayString(this Position position) + => $"({position.Line}, {position.Character})"; +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_Range.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_Range.cs new file mode 100644 index 00000000000..ce405277933 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_Range.cs @@ -0,0 +1,125 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static void Deconstruct(this Range range, out Position start, out Position end) + => (start, end) = (range.Start, range.End); + + public static void Deconstruct(this Range range, out int startLine, out int startCharacter, out int endLine, out int endCharacter) + => (startLine, startCharacter, endLine, endCharacter) = (range.Start.Line, range.Start.Character, range.End.Line, range.End.Character); + + public static LinePositionSpan ToLinePositionSpan(this Range range) + => new(range.Start.ToLinePosition(), range.End.ToLinePosition()); + + public static bool IntersectsOrTouches(this Range range, Range other) + { + if (range.IsBefore(other)) + { + return false; + } + + if (range.IsAfter(other)) + { + return false; + } + + return true; + } + + private static bool IsBefore(this Range range, Range other) => + range.End.Line < other.Start.Line || (range.End.Line == other.Start.Line && range.End.Character < other.Start.Character); + + private static bool IsAfter(this Range range, Range other) => + other.End.Line < range.Start.Line || (other.End.Line == range.Start.Line && other.End.Character < range.Start.Character); + + public static bool OverlapsWith(this Range range, Range other) + { + return range.ToLinePositionSpan().OverlapsWith(other.ToLinePositionSpan()); + } + + public static bool LineOverlapsWith(this Range range, Range other) + { + var overlapStart = range.Start.Line; + if (range.Start.Line.CompareTo(other.Start.Line) < 0) + { + overlapStart = other.Start.Line; + } + + var overlapEnd = range.End.Line; + if (range.End.Line.CompareTo(other.End.Line) > 0) + { + overlapEnd = other.End.Line; + } + + return overlapStart.CompareTo(overlapEnd) <= 0; + } + + public static bool Contains(this Range range, Range other) + { + + return range.Start.CompareTo(other.Start) <= 0 && range.End.CompareTo(other.End) >= 0; + } + + public static bool SpansMultipleLines(this Range range) + { + return range.Start.Line != range.End.Line; + } + + public static bool IsSingleLine(this Range range) + { + return range.Start.Line == range.End.Line; + } + + public static bool IsUndefined(this Range range) + { + return range == VsLspFactory.UndefinedRange; + } + + public static bool IsZeroWidth(this Range range) + { + return range.Start == range.End; + } + + public static int CompareTo(this Range range1, Range range2) + { + var result = range1.Start.CompareTo(range2.Start); + + if (result == 0) + { + result = range1.End.CompareTo(range2.End); + } + + return result; + } + + public static Range? Overlap(this Range range, Range other) + { + var overlapStart = range.Start; + if (range.Start.CompareTo(other.Start) < 0) + { + overlapStart = other.Start; + } + + var overlapEnd = range.End; + if (range.End.CompareTo(other.End) > 0) + { + overlapEnd = other.End; + } + + // Empty ranges do not overlap with any range. + if (overlapStart.CompareTo(overlapEnd) < 0) + { + return VsLspFactory.CreateRange(overlapStart, overlapEnd); + } + + return null; + } + + public static string ToDisplayString(this Range range) + => $"{range.Start.ToDisplayString()}-{range.End.ToDisplayString()}"; +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_RazorSyntaxTree.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_RazorSyntaxTree.cs new file mode 100644 index 00000000000..1bd0773e024 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_RazorSyntaxTree.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static SyntaxNode? FindInnermostNode( + this RazorSyntaxTree syntaxTree, + SourceText sourceText, + Position position, + bool includeWhitespace = false) + { + if (!sourceText.TryGetAbsoluteIndex(position, out var absoluteIndex)) + { + return null; + } + + return syntaxTree.Root.FindInnermostNode(absoluteIndex, includeWhitespace); + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SourceText.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SourceText.cs new file mode 100644 index 00000000000..0df608360b8 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SourceText.cs @@ -0,0 +1,50 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static int GetPosition(this SourceText text, Position position) + => text.GetPosition(position.ToLinePosition()); + + public static Position GetPosition(this SourceText text, int position) + => text.GetLinePosition(position).ToPosition(); + + public static Range GetRange(this SourceText text, TextSpan span) + => text.GetLinePositionSpan(span).ToRange(); + + public static Range GetRange(this SourceText text, SourceSpan span) + => text.GetLinePositionSpan(span).ToRange(); + + public static Range GetRange(this SourceText text, int start, int end) + => text.GetLinePositionSpan(start, end).ToRange(); + + public static Range GetZeroWidthRange(this SourceText text, int position) + => text.GetLinePosition(position).ToZeroWidthRange(); + + public static bool IsValidPosition(this SourceText text, Position position) + => text.IsValidPosition(position.Line, position.Character); + + public static bool TryGetAbsoluteIndex(this SourceText text, Position position, out int absoluteIndex) + => text.TryGetAbsoluteIndex(position.Line, position.Character, out absoluteIndex); + + public static int GetRequiredAbsoluteIndex(this SourceText text, Position position) + => text.GetRequiredAbsoluteIndex(position.Line, position.Character); + + public static TextSpan GetTextSpan(this SourceText text, Range range) + => text.GetTextSpan(range.Start.Line, range.Start.Character, range.End.Line, range.End.Character); + + public static bool TryGetSourceLocation(this SourceText text, Position position, out SourceLocation location) + => text.TryGetSourceLocation(position.Line, position.Character, out location); + + public static TextChange GetTextChange(this SourceText text, TextEdit edit) + => new(text.GetTextSpan(edit.Range), edit.NewText); + + public static TextEdit GetTextEdit(this SourceText text, TextChange change) + => VsLspFactory.CreateTextEdit(text.GetRange(change.Span), change.NewText.AssumeNotNull()); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SumTypeExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SumTypes.cs similarity index 69% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SumTypeExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SumTypes.cs index 7769608437d..6c75dd21d31 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/SumTypeExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SumTypes.cs @@ -1,13 +1,13 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; +using System.Collections.Generic; using System.Linq; -using Microsoft.VisualStudio.LanguageServer.Protocol; +using Microsoft.AspNetCore.Razor; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.VisualStudio.LanguageServer.Protocol; -internal static class SumTypeExtensions +internal static partial class VsLspExtensions { internal static int Count(this SumType[]> sumType) { @@ -15,14 +15,13 @@ internal static int Count(this SumType(); } internal static SumType ElementAt(this SumType[]> sumType, int elementIndex) @@ -31,14 +30,13 @@ internal static SumType El { return textDocumentEdits[elementIndex]; } - else if (sumType.TryGetSecond(out var edits)) + + if (sumType.TryGetSecond(out var edits)) { return edits[elementIndex]; } - else - { - throw new NotImplementedException("Shouldn't be possible"); - } + + return Assumed.Unreachable>(); } internal static SumType[] ToArray(this SumType[]> sumType) @@ -47,14 +45,13 @@ internal static SumType[] { return textDocumentEdit.Select(s => (SumType)s).ToArray(); } - else if (sumType.TryGetSecond(out var edits)) + + if (sumType.TryGetSecond(out var edits)) { return edits.ToArray(); } - else - { - throw new NotImplementedException("Shouldn't be possible"); - } + + return Assumed.Unreachable[]>(); } internal static SumType First(this SumType[]> sumType) @@ -63,14 +60,13 @@ internal static SumType Fi { return textDocumentEdits.First(); } - else if (sumType.TryGetSecond(out var edits)) + + if (sumType.TryGetSecond(out var edits)) { return edits.First(); } - else - { - throw new NotImplementedException("Shouldn't be possible"); - } + + return Assumed.Unreachable>(); } internal static SumType Last(this SumType[]> sumType) @@ -79,13 +75,12 @@ internal static SumType La { return textDocumentEdits.Last(); } - else if (sumType.TryGetSecond(out var edits)) + + if (sumType.TryGetSecond(out var edits)) { return edits.Last(); } - else - { - throw new NotImplementedException("Shouldn't be possible"); - } + + return Assumed.Unreachable>(); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SyntaxNode.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SyntaxNode.cs new file mode 100644 index 00000000000..92c243bacb5 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_SyntaxNode.cs @@ -0,0 +1,80 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; +using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static Range GetRange(this SyntaxNode node, RazorSourceDocument source) + { + var linePositionSpan = node.GetLinePositionSpan(source); + + return VsLspFactory.CreateRange(linePositionSpan); + } + + public static Range? GetRangeWithoutWhitespace(this SyntaxNode node, RazorSourceDocument source) + { + var tokens = node.GetTokens(); + + SyntaxToken? firstToken = null; + for (var i = 0; i < tokens.Count; i++) + { + var token = tokens[i]; + if (!token.IsWhitespace()) + { + firstToken = token; + break; + } + } + + SyntaxToken? lastToken = null; + for (var i = tokens.Count - 1; i >= 0; i--) + { + var token = tokens[i]; + if (!token.IsWhitespace()) + { + lastToken = token; + break; + } + } + + if (firstToken is null && lastToken is null) + { + return null; + } + + var startPositionSpan = GetLinePositionSpan(firstToken, source, node.SpanStart); + var endPositionSpan = GetLinePositionSpan(lastToken, source, node.SpanStart); + + return VsLspFactory.CreateRange(startPositionSpan.Start, endPositionSpan.End); + + // This is needed because SyntaxToken positions taken from GetTokens + // are relative to their parent node and not to the document. + static LinePositionSpan GetLinePositionSpan(SyntaxNode? node, RazorSourceDocument source, int parentStart) + { + ArgHelper.ThrowIfNull(node); + ArgHelper.ThrowIfNull(source); + + var sourceText = source.Text; + + var start = node.Position + parentStart; + var end = node.EndPosition + parentStart; + + if (start == sourceText.Length && node.FullWidth == 0) + { + // Marker symbol at the end of the document. + var location = node.GetSourceLocation(source); + var position = location.ToLinePosition(); + return new LinePositionSpan(position, position); + } + + return sourceText.GetLinePositionSpan(start, end); + } + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextChange.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextChange.cs new file mode 100644 index 00000000000..5feb06ba64f --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextChange.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static partial class VsLspExtensions +{ + public static RazorTextChange ToRazorTextChange(this TextChange textChange) + { + return new RazorTextChange() + { + Span = new RazorTextSpan() + { + Start = textChange.Span.Start, + Length = textChange.Span.Length, + }, + NewText = textChange.NewText + }; + } +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextDocumentIdentifierExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs similarity index 71% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextDocumentIdentifierExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs index 05262a6f401..44017ad6256 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/TextDocumentIdentifierExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_TextDocumentIdentifier.cs @@ -1,11 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using Microsoft.VisualStudio.LanguageServer.Protocol; +namespace Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -internal static class TextDocumentIdentifierExtensions +internal static partial class VsLspExtensions { public static VSProjectContext? GetProjectContext(this TextDocumentIdentifier textDocumentIdentifier) => textDocumentIdentifier is VSTextDocumentIdentifier vsIdentifier diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VSInternalClientCapabilitiesExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_VSInternalClientCapabilities.cs similarity index 81% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VSInternalClientCapabilitiesExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_VSInternalClientCapabilities.cs index d26a6fbca3e..ef801c03cec 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VSInternalClientCapabilitiesExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_VSInternalClientCapabilities.cs @@ -1,11 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using Microsoft.VisualStudio.LanguageServer.Protocol; +namespace Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; - -internal static class VSInternalClientCapabilitiesExtensions +internal static partial class VsLspExtensions { internal static VSInternalClientCapabilities ToVSInternalClientCapabilities(this ClientCapabilities clientCapabilities) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VSProjectContextExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_VSProjectContext.cs similarity index 69% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VSProjectContextExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_VSProjectContext.cs index baed85e4831..959c14c116a 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VSProjectContextExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_VSProjectContext.cs @@ -2,11 +2,10 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using Microsoft.AspNetCore.Razor.ProjectSystem; -using Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.VisualStudio.LanguageServer.Protocol; -internal static class VSProjectContextExtensions +internal static partial class VsLspExtensions { internal static ProjectKey ToProjectKey(this VSProjectContext projectContext) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/WorkspaceEditExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_WorkspaceEdit.cs similarity index 89% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/WorkspaceEditExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_WorkspaceEdit.cs index 2ebe36d715c..7c732521908 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/WorkspaceEditExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspExtensions_WorkspaceEdit.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using Microsoft.VisualStudio.LanguageServer.Protocol; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.VisualStudio.LanguageServer.Protocol; -internal static class WorkspaceEditExtensions +internal static partial class VsLspExtensions { public static bool TryGetDocumentChanges(this WorkspaceEdit workspaceEdit, [NotNullWhen(true)] out TextDocumentEdit[]? documentChanges) { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspFactory.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspFactory.cs new file mode 100644 index 00000000000..5b29d44cc60 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/VsLspFactory.cs @@ -0,0 +1,188 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Diagnostics; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.VisualStudio.LanguageServer.Protocol; + +internal static class VsLspFactory +{ + private static readonly Position s_defaultPosition = new(0, 0); + + private static readonly Range s_defaultRange = new() + { + Start = s_defaultPosition, + End = s_defaultPosition + }; + + private static readonly Position s_undefinedPosition = new(-1, -1); + + private static readonly Range s_undefinedRange = new() + { + Start = s_undefinedPosition, + End = s_undefinedPosition + }; + + /// + /// Returns a for line 0 and character 0. + /// + public static Position DefaultPosition + { + get + { + var defaultPosition = s_defaultPosition; + + // Since Position is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + defaultPosition.Line == 0 && + defaultPosition.Character == 0, + $"{nameof(VsLspFactory)}.{nameof(DefaultPosition)} has been corrupted. Current value: {defaultPosition.ToDisplayString()}"); + + return defaultPosition; + } + } + + /// + /// Returns a for starting line 0 and character 0, + /// and ending line 0 and character 0. + /// + public static Range DefaultRange + { + get + { + var defaultRange = s_defaultRange; + + // Since Range is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + defaultRange.Start.Line == 0 && + defaultRange.Start.Character == 0 && + defaultRange.End.Line == 0 && + defaultRange.End.Character == 0, + $"{nameof(VsLspFactory)}.{nameof(DefaultRange)} has been corrupted. Current value: {defaultRange.ToDisplayString()}"); + + return defaultRange; + } + } + + public static Position UndefinedPosition + { + get + { + var undefinedPosition = s_undefinedPosition; + + // Since Position is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + undefinedPosition.Line == -1 && + undefinedPosition.Character == -1, + $"{nameof(VsLspFactory)}.{nameof(UndefinedPosition)} has been corrupted. Current value: {undefinedPosition.ToDisplayString()}"); + + return undefinedPosition; + } + } + + public static Range UndefinedRange + { + get + { + var undefinedRange = s_undefinedRange; + + // Since Range is mutable, it's possible that something might modify it. If that happens, we should know! + Debug.Assert( + undefinedRange.Start.Line == -1 && + undefinedRange.Start.Character == -1 && + undefinedRange.End.Line == -1 && + undefinedRange.End.Character == -1, + $"{nameof(VsLspFactory)}.{nameof(UndefinedRange)} has been corrupted. Current value: {undefinedRange.ToDisplayString()}"); + + return undefinedRange; + } + } + + public static Position CreatePosition(int line, int character) + => (line, character) switch + { + (0, 0) => DefaultPosition, + (-1, -1) => UndefinedPosition, + _ => new(line, character) + }; + + public static Position CreatePosition(LinePosition linePosition) + => CreatePosition(linePosition.Line, linePosition.Character); + + public static Position CreatePosition((int line, int character) position) + => CreatePosition(position.line, position.character); + + public static Range CreateRange(int startLine, int startCharacter, int endLine, int endCharacter) + => startLine == endLine && startCharacter == endCharacter + ? CreateZeroWidthRange(startLine, startCharacter) + : CreateRange(CreatePosition(startLine, startCharacter), CreatePosition(endLine, endCharacter)); + + public static Range CreateRange(Position start, Position end) + => new() { Start = start, End = end }; + + public static Range CreateRange(LinePosition start, LinePosition end) + => CreateRange(start.Line, start.Character, end.Line, end.Character); + + public static Range CreateRange((int line, int character) start, (int line, int character) end) + => CreateRange(start.line, start.character, end.line, end.character); + + public static Range CreateRange(LinePositionSpan span) + => CreateRange(span.Start, span.End); + + public static Range CreateZeroWidthRange(int line, int character) + => (line, character) switch + { + (0, 0) => DefaultRange, + (-1, -1) => UndefinedRange, + _ => CreateZeroWidthRange(CreatePosition(line, character)) + }; + + public static Range CreateZeroWidthRange(Position position) + => CreateRange(position, position); + + public static Range CreateZeroWidthRange(LinePosition position) + => CreateRange(position, position); + + public static Range CreateZeroWidthRange((int line, int character) position) + => CreateRange(position, position); + + public static Range CreateSingleLineRange(int line, int character, int length) + => CreateRange(line, character, line, character + length); + + public static Range CreateSingleLineRange(Position start, int length) + => CreateRange(start, CreatePosition(start.Line, start.Character + length)); + + public static Range CreateSingleLineRange(LinePosition start, int length) + => CreateSingleLineRange(start.Line, start.Character, length); + + public static Range CreateSingleLineRange((int line, int character) start, int length) + => CreateRange(CreatePosition(start), CreatePosition(start.line, start.character + length)); + + public static TextEdit CreateTextEdit(Range range, string newText) + => new() { Range = range, NewText = newText }; + + public static TextEdit CreateTextEdit(LinePositionSpan span, string newText) + => CreateTextEdit(CreateRange(span), newText); + + public static TextEdit CreateTextEdit(int startLine, int startCharacter, int endLine, int endCharacter, string newText) + => CreateTextEdit(CreateRange(startLine, startCharacter, endLine, endCharacter), newText); + + public static TextEdit CreateTextEdit(Position start, Position end, string newText) + => CreateTextEdit(CreateRange(start, end), newText); + + public static TextEdit CreateTextEdit(LinePosition start, LinePosition end, string newText) + => CreateTextEdit(CreateRange(start, end), newText); + + public static TextEdit CreateTextEdit(int line, int character, string newText) + => CreateTextEdit(CreateZeroWidthRange(line, character), newText); + + public static TextEdit CreateTextEdit(Position position, string newText) + => CreateTextEdit(CreateZeroWidthRange(position), newText); + + public static TextEdit CreateTextEdit(LinePosition position, string newText) + => CreateTextEdit(CreateZeroWidthRange(position.Line, position.Character), newText); + + public static TextEdit CreateTextEdit((int line, int character) position, string newText) + => CreateTextEdit(CreateZeroWidthRange(position), newText); +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/AbstractSyntaxNodeFoldingProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/AbstractSyntaxNodeFoldingProvider.cs index 116584c3d4d..58e81b4112c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/AbstractSyntaxNodeFoldingProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/AbstractSyntaxNodeFoldingProvider.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.PooledObjects; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.FoldingRanges; @@ -15,21 +15,20 @@ internal abstract class AbstractSyntaxNodeFoldingProvider : IRazorFolding { public ImmutableArray GetFoldingRanges(RazorCodeDocument codeDocument) { - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var syntaxTree = codeDocument.GetSyntaxTree(); var nodes = GetFoldableNodes(syntaxTree); using var builder = new PooledArrayBuilder(nodes.Length); foreach (var node in nodes) { - sourceText.GetLineAndOffset(node.Span.Start, out var startLine, out var startOffset); - sourceText.GetLineAndOffset(node.Span.End, out var endLine, out var endOffset); + var (start, end) = sourceText.GetLinePositionSpan(node.Span); var foldingRange = new FoldingRange() { - StartCharacter = startOffset, - StartLine = startLine, - EndCharacter = endOffset, - EndLine = endLine, + StartCharacter = start.Character, + StartLine = start.Line, + EndCharacter = end.Character, + EndLine = end.Line, // Directives remove the "@" but for collapsing we want to keep it for users. // Shows "@code" instead of "code". diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs index 8dadd23a28e..def3567e4b3 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/FoldingRangeService.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -86,7 +85,7 @@ private FoldingRange FixFoldingRangeStart(FoldingRange range, RazorCodeDocument { Debug.Assert(range.StartLine < range.EndLine); - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var startLine = range.StartLine; if (startLine >= sourceText.Lines.Count) @@ -101,13 +100,11 @@ private FoldingRange FixFoldingRangeStart(FoldingRange range, RazorCodeDocument // Search from the end of the line to the beginning for the first non whitespace character. We want that // to be the offset for the range - var offset = sourceText.GetLastNonWhitespaceOffset(lineSpan, out _); - - if (offset.HasValue) + if (sourceText.TryGetLastNonWhitespaceOffset(lineSpan, out var offset)) { // +1 to the offset value because the helper goes to the character position // that we want to be after. Make sure we don't exceed the line end - var newCharacter = Math.Min(offset.Value + 1, lineSpan.Length); + var newCharacter = Math.Min(offset + 1, lineSpan.Length); range.StartCharacter = newCharacter; range.CollapsedText = null; // Let the client decide what to show diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorCodeBlockFoldingProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorCodeBlockFoldingProvider.cs index 9549cfa69f2..45726b76ca0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorCodeBlockFoldingProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorCodeBlockFoldingProvider.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.CodeAnalysis.Razor.FoldingRanges; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorFileUsingsFoldingSyntaxWalker.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorFileUsingsFoldingSyntaxWalker.cs index d6010cf068b..6dd4a046bf8 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorFileUsingsFoldingSyntaxWalker.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/RazorFileUsingsFoldingSyntaxWalker.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.FoldingRanges; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/SectionDirectiveFoldingProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/SectionDirectiveFoldingProvider.cs index b2b9950f55e..b5f70cfcd14 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/SectionDirectiveFoldingProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/FoldingRanges/SectionDirectiveFoldingProvider.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.CodeAnalysis.Razor.FoldingRanges; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs index 5d629ed5136..ad7e470293c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/LinkedEditingRange/LinkedEditingRangeHelper.cs @@ -5,8 +5,6 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; -using Microsoft.CodeAnalysis.Razor.Logging; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using RazorSyntaxToken = Microsoft.AspNetCore.Razor.Language.Syntax.SyntaxToken; @@ -20,9 +18,9 @@ internal static class LinkedEditingRangeHelper // https://github.com/dotnet/aspnetcore/blob/9da42b9fab4c61fe46627ac0c6877905ec845d5a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Legacy/HtmlTokenizer.cs public static readonly string WordPattern = @"!?[^ <>!\/\?\[\]=""\\@" + Environment.NewLine + "]+"; - public static LinePositionSpan[]? GetLinkedSpans(LinePosition linePosition, RazorCodeDocument codeDocument, ILogger logger) + public static LinePositionSpan[]? GetLinkedSpans(LinePosition linePosition, RazorCodeDocument codeDocument) { - if (GetSourceLocation(linePosition, codeDocument, logger) is not { } validLocation) + if (!codeDocument.Source.Text.TryGetSourceLocation(linePosition, out var validLocation)) { return null; } @@ -43,23 +41,6 @@ internal static class LinkedEditingRangeHelper return null; } - private static SourceLocation? GetSourceLocation( - LinePosition linePosition, - RazorCodeDocument codeDocument, - ILogger logger) - { - var sourceText = codeDocument.GetSourceText(); - - if (linePosition.ToPosition().TryGetSourceLocation(sourceText, logger, out var location)) - { - return location; - } - else - { - return null; - } - } - private static bool TryGetNearestMarkupNameTokens( RazorSyntaxTree syntaxTree, SourceLocation location, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Logging/ILoggerExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Logging/ILoggerExtensions.cs index 7fabf3ccd9a..8f46e524a91 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Logging/ILoggerExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Logging/ILoggerExtensions.cs @@ -16,6 +16,14 @@ public static void Log(this ILogger logger, LogLevel logLevel, [InterpolatedStri } } + public static void Log(this ILogger logger, LogLevel logLevel, string message) + { + if (logger.IsEnabled(logLevel)) + { + logger.Log(logLevel, message, exception: null); + } + } + public static void LogTrace(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref TraceLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) @@ -24,6 +32,14 @@ public static void LogTrace(this ILogger logger, [InterpolatedStringHandlerArgum } } + public static void LogTrace(this ILogger logger, string message) + { + if (logger.IsEnabled(LogLevel.Trace)) + { + logger.Log(LogLevel.Trace, message); + } + } + public static void LogDebug(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref DebugLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) @@ -32,6 +48,14 @@ public static void LogDebug(this ILogger logger, [InterpolatedStringHandlerArgum } } + public static void LogDebug(this ILogger logger, string message) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + logger.Log(LogLevel.Debug, message); + } + } + public static void LogInformation(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref InformationLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) @@ -40,6 +64,14 @@ public static void LogInformation(this ILogger logger, [InterpolatedStringHandle } } + public static void LogInformation(this ILogger logger, string message) + { + if (logger.IsEnabled(LogLevel.Information)) + { + logger.Log(LogLevel.Information, message); + } + } + public static void LogWarning(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref WarningLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) @@ -48,7 +80,7 @@ public static void LogWarning(this ILogger logger, [InterpolatedStringHandlerArg } } - public static void LogWarning(this ILogger logger, Exception? exception, [InterpolatedStringHandlerArgument(nameof(logger))] ref WarningLogMessageInterpolatedStringHandler message) + public static void LogWarning(this ILogger logger, Exception exception, [InterpolatedStringHandlerArgument(nameof(logger))] ref WarningLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) { @@ -56,11 +88,19 @@ public static void LogWarning(this ILogger logger, Exception? exception, [Interp } } - public static void LogError(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref ErrorLogMessageInterpolatedStringHandler message) + public static void LogWarning(this ILogger logger, Exception exception, string message) { - if (message.IsEnabled) + if (logger.IsEnabled(LogLevel.Warning)) { - logger.Log(LogLevel.Error, message.ToString(), exception: null); + logger.Log(LogLevel.Warning, message, exception); + } + } + + public static void LogWarning(this ILogger logger, string message) + { + if (logger.IsEnabled(LogLevel.Warning)) + { + logger.Log(LogLevel.Warning, message); } } @@ -72,7 +112,7 @@ public static void LogError(this ILogger logger, Exception exception) } } - public static void LogError(this ILogger logger, Exception? exception, [InterpolatedStringHandlerArgument(nameof(logger))] ref ErrorLogMessageInterpolatedStringHandler message) + public static void LogError(this ILogger logger, Exception exception, [InterpolatedStringHandlerArgument(nameof(logger))] ref ErrorLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) { @@ -80,6 +120,30 @@ public static void LogError(this ILogger logger, Exception? exception, [Interpol } } + public static void LogError(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref ErrorLogMessageInterpolatedStringHandler message) + { + if (message.IsEnabled) + { + logger.Log(LogLevel.Error, message.ToString(), exception: null); + } + } + + public static void LogError(this ILogger logger, Exception exception, string message) + { + if (logger.IsEnabled(LogLevel.Error)) + { + logger.Log(LogLevel.Error, message, exception); + } + } + + public static void LogError(this ILogger logger, string message) + { + if (logger.IsEnabled(LogLevel.Error)) + { + logger.Log(LogLevel.Error, message); + } + } + public static void LogCritical(this ILogger logger, Exception exception) { if (logger.IsEnabled(LogLevel.Critical)) @@ -88,11 +152,35 @@ public static void LogCritical(this ILogger logger, Exception exception) } } - public static void LogCritical(this ILogger logger, Exception? exception, [InterpolatedStringHandlerArgument(nameof(logger))] ref CriticalLogMessageInterpolatedStringHandler message) + public static void LogCritical(this ILogger logger, [InterpolatedStringHandlerArgument(nameof(logger))] ref CriticalLogMessageInterpolatedStringHandler message) + { + if (message.IsEnabled) + { + logger.Log(LogLevel.Critical, message.ToString(), exception: null); + } + } + + public static void LogCritical(this ILogger logger, Exception exception, [InterpolatedStringHandlerArgument(nameof(logger))] ref CriticalLogMessageInterpolatedStringHandler message) { if (message.IsEnabled) { logger.Log(LogLevel.Critical, message.ToString(), exception); } } + + public static void LogCritical(this ILogger logger, Exception exception, string message) + { + if (logger.IsEnabled(LogLevel.Critical)) + { + logger.Log(LogLevel.Critical, message, exception); + } + } + + public static void LogCritical(this ILogger logger, string message) + { + if (logger.IsEnabled(LogLevel.Critical)) + { + logger.Log(LogLevel.Critical, message); + } + } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs index 2b8c7a2deb7..36a01ebd20f 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/DocumentContext.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentContextFactoryExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentContextFactoryExtensions.cs index 2264ce4399e..519212b9df7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentContextFactoryExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentContextFactoryExtensions.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics.CodeAnalysis; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IDocumentSnapshotExtensions.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs similarity index 97% rename from src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IDocumentSnapshotExtensions.cs rename to src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs index a8382f236e7..7e97774f9ed 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Extensions/IDocumentSnapshotExtensions.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/ProjectSystem/IDocumentSnapshotExtensions.cs @@ -6,9 +6,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.CodeAnalysis.Razor.ProjectSystem; -namespace Microsoft.CodeAnalysis.Razor.Workspaces; +namespace Microsoft.CodeAnalysis.Razor.ProjectSystem; internal static class IDocumentSnapshotExtensions { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DocumentHighlight/RemoteDocumentHighlight.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DocumentHighlight/RemoteDocumentHighlight.cs index a0494059d38..c40741ebff5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DocumentHighlight/RemoteDocumentHighlight.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/DocumentHighlight/RemoteDocumentHighlight.cs @@ -2,27 +2,26 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Runtime.Serialization; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; -using RLSP = Roslyn.LanguageServer.Protocol; +using static Roslyn.LanguageServer.Protocol.RoslynLspExtensions; +using RoslynDocumentHighlight = Roslyn.LanguageServer.Protocol.DocumentHighlight; +using VsDocumentHighlight = Microsoft.VisualStudio.LanguageServer.Protocol.DocumentHighlight; namespace Microsoft.CodeAnalysis.Razor.Protocol.DocumentHighlight; -using DocumentHighlight = VisualStudio.LanguageServer.Protocol.DocumentHighlight; - [DataContract] internal readonly record struct RemoteDocumentHighlight( - [property: DataMember(Order = 0)] LinePositionSpan Position, + [property: DataMember(Order = 0)] LinePositionSpan Span, [property: DataMember(Order = 1)] DocumentHighlightKind Kind) { - public static RemoteDocumentHighlight FromRLSPDocumentHighlight(RLSP.DocumentHighlight h) - => new RemoteDocumentHighlight(h.Range.ToLinePositionSpan(), (DocumentHighlightKind)h.Kind); + public static RemoteDocumentHighlight FromRoslynDocumentHighlight(RoslynDocumentHighlight highlight) + => new(highlight.Range.ToLinePositionSpan(), (DocumentHighlightKind)highlight.Kind); - public static DocumentHighlight ToLspDocumentHighlight(RemoteDocumentHighlight r) - => new DocumentHighlight + public static VsDocumentHighlight ToVsDocumentHighlight(RemoteDocumentHighlight highlight) + => new() { - Range = r.Position.ToRange(), - Kind = r.Kind + Range = VsLspExtensions.ToRange(highlight.Span), + Kind = highlight.Kind }; } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/Folding/RemoteFoldingRange.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/Folding/RemoteFoldingRange.cs index 933cfeac0a8..59d83bb8603 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/Folding/RemoteFoldingRange.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Protocol/Folding/RemoteFoldingRange.cs @@ -20,8 +20,8 @@ public override string ToString() return $"({StartLine}, {StartCharacter})-({EndLine}, {EndCharacter}), {Kind}, {CollapsedText}"; } - public static RemoteFoldingRange FromLspFoldingRange(FoldingRange r) - => new RemoteFoldingRange( + public static RemoteFoldingRange FromVsFoldingRange(FoldingRange r) + => new( r.StartLine, r.StartCharacter, r.EndLine, @@ -29,8 +29,8 @@ public static RemoteFoldingRange FromLspFoldingRange(FoldingRange r) r.Kind?.Value, r.CollapsedText); - public static FoldingRange ToLspFoldingRange(RemoteFoldingRange r) - => new FoldingRange + public static FoldingRange ToVsFoldingRange(RemoteFoldingRange r) + => new() { StartLine = r.StartLine, StartCharacter = r.StartCharacter, diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs index 88a97e49c9a..2fa4acdd54d 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs @@ -68,7 +68,7 @@ internal abstract class AbstractRazorSemanticTokensInfoService( cancellationToken.ThrowIfCancellationRequested(); - var textSpan = span.ToTextSpan(codeDocument.Source.Text); + var textSpan = codeDocument.Source.Text.GetTextSpan(span); var razorSemanticRanges = SemanticTokensVisitor.GetSemanticRanges(codeDocument, textSpan, _semanticTokensLegendService, colorBackground); ImmutableArray? csharpSemanticRangesResult = null; @@ -184,7 +184,7 @@ private static ImmutableArray CombineSemanticRanges(ImmutableArra razorRanges.SetCapacityIfLarger(csharpResponse.Length / TokenSize); var textClassification = _semanticTokensLegendService.TokenTypes.MarkupTextLiteral; - var razorSource = codeDocument.GetSourceText(); + var razorSource = codeDocument.Source.Text; SemanticRange previousSemanticRange = default; LinePositionSpan? previousRazorSemanticRange = null; @@ -205,7 +205,7 @@ private static ImmutableArray CombineSemanticRanges(ImmutableArra if (colorBackground) { tokenModifiers |= _semanticTokensLegendService.TokenModifiers.RazorCodeModifier; - AddAdditionalCSharpWhitespaceRanges(razorRanges, textClassification, razorSource, previousRazorSemanticRange, originalRange, _logger); + AddAdditionalCSharpWhitespaceRanges(razorRanges, textClassification, razorSource, previousRazorSemanticRange, originalRange); } razorRanges.Add(new SemanticRange(semanticRange.Kind, originalRange.Start.Line, originalRange.Start.Character, originalRange.End.Line, originalRange.End.Character, tokenModifiers, fromRazor: false)); @@ -220,14 +220,14 @@ private static ImmutableArray CombineSemanticRanges(ImmutableArra return razorRanges.DrainToImmutable(); } - private void AddAdditionalCSharpWhitespaceRanges(ImmutableArray.Builder razorRanges, int textClassification, SourceText razorSource, LinePositionSpan? previousRazorSemanticRange, LinePositionSpan originalRange, ILogger logger) + private void AddAdditionalCSharpWhitespaceRanges(ImmutableArray.Builder razorRanges, int textClassification, SourceText razorSource, LinePositionSpan? previousRazorSemanticRange, LinePositionSpan originalRange) { var startLine = originalRange.Start.Line; var startChar = originalRange.Start.Character; if (previousRazorSemanticRange is { } previousRange && previousRange.End.Line == startLine && previousRange.End.Character < startChar && - previousRange.End.TryGetAbsoluteIndex(razorSource, logger, out var previousSpanEndIndex) && + razorSource.TryGetAbsoluteIndex(previousRange.End, out var previousSpanEndIndex) && ContainsOnlySpacesOrTabs(razorSource, previousSpanEndIndex + 1, startChar - previousRange.End.Character - 1)) { // we're on the same line as previous, lets extend ours to include whitespace between us and the proceeding range @@ -235,7 +235,7 @@ private void AddAdditionalCSharpWhitespaceRanges(ImmutableArray.B } else if (startChar > 0 && previousRazorSemanticRange?.End.Line != startLine && - originalRange.Start.TryGetAbsoluteIndex(razorSource, logger, out var originalRangeStartIndex) && + razorSource.TryGetAbsoluteIndex(originalRange.Start, out var originalRangeStartIndex) && ContainsOnlySpacesOrTabs(razorSource, originalRangeStartIndex - startChar + 1, startChar - 1)) { // We're on a new line, and the start of the line is only whitespace, so give that a background color too @@ -262,8 +262,8 @@ internal static bool TryGetSortedCSharpRanges(RazorCodeDocument codeDocument, Li { using var _ = ArrayBuilderPool.GetPooledObject(out var csharpRanges); var csharpSourceText = codeDocument.GetCSharpSourceText(); - var sourceText = codeDocument.GetSourceText(); - var textSpan = razorRange.ToTextSpan(sourceText); + var sourceText = codeDocument.Source.Text; + var textSpan = sourceText.GetTextSpan(razorRange); var csharpDoc = codeDocument.GetCSharpDocument(); // We want to find the min and max C# source mapping that corresponds with our Razor range. @@ -273,7 +273,7 @@ internal static bool TryGetSortedCSharpRanges(RazorCodeDocument codeDocument, Li if (textSpan.OverlapsWith(mappedTextSpan)) { - var mappedRange = mapping.GeneratedSpan.ToLinePositionSpan(csharpSourceText); + var mappedRange = csharpSourceText.GetLinePositionSpan(mapping.GeneratedSpan); csharpRanges.Add(mappedRange); } } @@ -327,7 +327,7 @@ private static int[] ConvertSemanticRangesToSemanticTokensData( { SemanticRange previousResult = default; - var sourceText = razorCodeDocument.GetSourceText(); + var sourceText = razorCodeDocument.Source.Text; // We don't bother filtering out duplicate ranges (eg, where C# and Razor both have opinions), but instead take advantage of // our sort algorithm to be correct, so we can skip duplicates here. That means our final array may end up smaller than the diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs index ebaa0c1559e..f26b3029ee7 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticTokensVisitor.cs @@ -6,7 +6,6 @@ using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.PooledObjects; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Razor.SemanticTokens; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs index 5c940f5dbb8..61252f6d011 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/DocumentHighlight/RemoteDocumentHighlightService.cs @@ -14,6 +14,8 @@ using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; +using static Microsoft.VisualStudio.LanguageServer.Protocol.VsLspExtensions; +using static Roslyn.LanguageServer.Protocol.RoslynLspExtensions; using Response = Microsoft.CodeAnalysis.Razor.Remote.RemoteResponse; namespace Microsoft.CodeAnalysis.Remote.Razor; @@ -46,7 +48,7 @@ private async ValueTask GetHighlightsAsync( CancellationToken cancellationToken) { var sourceText = await context.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (!sourceText.TryGetAbsoluteIndex(position.Line, position.Character, out var index)) + if (!sourceText.TryGetAbsoluteIndex(position, out var index)) { return Response.NoFurtherHandling; } @@ -78,8 +80,8 @@ private async ValueTask GetHighlightsAsync( { if (_documentMappingService.TryMapToHostDocumentRange(csharpDocument, highlight.Range.ToLinePositionSpan(), out var mappedRange)) { - highlight.Range = mappedRange.ToRLSPRange(); - results.Add(RemoteDocumentHighlight.FromRLSPDocumentHighlight(highlight)); + highlight.Range = Roslyn.LanguageServer.Protocol.RoslynLspExtensions.ToRange(mappedRange); + results.Add(RemoteDocumentHighlight.FromRoslynDocumentHighlight(highlight)); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/RemoteFoldingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/RemoteFoldingRangeService.cs index 92c114a5816..5fed4a0a437 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/RemoteFoldingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/FoldingRanges/RemoteFoldingRangeService.cs @@ -48,11 +48,11 @@ private async ValueTask> GetFoldingRangesAsyn var csharpRanges = await ExternalHandlers.FoldingRanges.GetFoldingRangesAsync(generatedDocument, cancellationToken).ConfigureAwait(false); var convertedCSharp = csharpRanges.SelectAsArray(ToFoldingRange); - var convertedHtml = htmlRanges.SelectAsArray(RemoteFoldingRange.ToLspFoldingRange); + var convertedHtml = htmlRanges.SelectAsArray(RemoteFoldingRange.ToVsFoldingRange); var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); return _foldingRangeService.GetFoldingRanges(codeDocument, convertedCSharp, convertedHtml, cancellationToken) - .SelectAsArray(RemoteFoldingRange.FromLspFoldingRange); + .SelectAsArray(RemoteFoldingRange.FromVsFoldingRange); } public static FoldingRange ToFoldingRange(Roslyn.LanguageServer.Protocol.FoldingRange r) diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/HtmlDocuments/RemoteHtmlDocumentService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/HtmlDocuments/RemoteHtmlDocumentService.cs index c8492edc1df..3304b1b47b9 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/HtmlDocuments/RemoteHtmlDocumentService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/HtmlDocuments/RemoteHtmlDocumentService.cs @@ -3,9 +3,9 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Remote; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; namespace Microsoft.CodeAnalysis.Remote.Razor; diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/LinkedEditingRange/RemoteLinkedEditingRangeService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/LinkedEditingRange/RemoteLinkedEditingRangeService.cs index d27a11f7ce3..cc09f5df0c5 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/LinkedEditingRange/RemoteLinkedEditingRangeService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/LinkedEditingRange/RemoteLinkedEditingRangeService.cs @@ -42,6 +42,6 @@ protected override IRemoteLinkedEditingRangeService CreateService(in ServiceArgs var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); - return LinkedEditingRangeHelper.GetLinkedSpans(linePosition, codeDocument, Logger); + return LinkedEditingRangeHelper.GetLinkedSpans(linePosition, codeDocument); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs index dc94aa76584..08971e58191 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SignatureHelp/RemoteSignatureHelpService.cs @@ -39,7 +39,7 @@ protected override IRemoteSignatureHelpService CreateService(in ServiceArgs args { var codeDocument = await context.GetCodeDocumentAsync(cancellationToken).ConfigureAwait(false); var linePosition = new LinePosition(position.Line, position.Character); - var absoluteIndex = linePosition.GetRequiredAbsoluteIndex(codeDocument.Source.Text, logger: null); + var absoluteIndex = codeDocument.Source.Text.GetRequiredAbsoluteIndex(linePosition); var generatedDocument = await context.GetGeneratedDocumentAsync(_filePathService, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs index 632f4b59e83..db920ccee6c 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/UriPresentation/RemoteUriPresentationService.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.DocumentPresentation; +using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.Workspaces; @@ -45,7 +46,7 @@ private async ValueTask GetPresentationAsync( CancellationToken cancellationToken) { var sourceText = await context.GetSourceTextAsync(cancellationToken).ConfigureAwait(false); - if (!sourceText.TryGetAbsoluteIndex(span.Start.Line, span.Start.Character, out var index)) + if (!sourceText.TryGetAbsoluteIndex(span.Start, out var index)) { // If the position is invalid then we shouldn't expect to be able to handle a Html response return Response.NoFurtherHandling; @@ -100,6 +101,6 @@ private async ValueTask GetPresentationAsync( return Response.CallHtml; } - return Response.Results(new TextChange(span.ToTextSpan(sourceText), tag)); + return Response.Results(new TextChange(sourceText.GetTextSpan(span), tag)); } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Debugging/RazorBreakpointResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Debugging/RazorBreakpointResolver.cs index f7b71208c08..a9dfe15d5bc 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Debugging/RazorBreakpointResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Debugging/RazorBreakpointResolver.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.Text; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.Debugging; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DocumentExcerptService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DocumentExcerptService.cs index 7a2610feb48..6cf1bedf778 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DocumentExcerptService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/DocumentExcerptService.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; namespace Microsoft.VisualStudio.Razor.DynamicFiles; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs index e2c63bc0a70..bef6c7edd60 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/DynamicFiles/RazorSpanMappingService.cs @@ -86,7 +86,7 @@ internal static bool TryGetMappedSpans(TextSpan span, SourceText source, RazorCS { // This span mapping contains the span. mappedSpan = new TextSpan(original.Start + leftOffset, (original.End + rightOffset) - (original.Start + leftOffset)); - linePositionSpan = source.Lines.GetLinePositionSpan(mappedSpan); + linePositionSpan = source.GetLinePositionSpan(mappedSpan); return true; } } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs index 568382eaa3d..e832f7561d8 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostDocumentHighlightPresentationEndpoint.cs @@ -71,7 +71,7 @@ internal class CohostDocumentHighlightEndpoint( // If we got a response back, then either Razor or C# wants to do something with this, so we're good to go if (csharpResult.Result is { } highlights) { - return highlights.Select(RemoteDocumentHighlight.ToLspDocumentHighlight).ToArray(); + return highlights.Select(RemoteDocumentHighlight.ToVsDocumentHighlight).ToArray(); } if (csharpResult.StopHandling) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs index 41741514926..be3ab94f529 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostFoldingRangeEndpoint.cs @@ -88,7 +88,7 @@ internal class CohostFoldingRangeEndpoint( { _logger.LogDebug($"Got a total of {allRanges.Length} ranges back from OOP"); - return allRanges.Select(RemoteFoldingRange.ToLspFoldingRange).ToArray(); + return allRanges.Select(RemoteFoldingRange.ToVsFoldingRange).ToArray(); } return null; @@ -122,7 +122,7 @@ internal class CohostFoldingRangeEndpoint( return null; } - return result.Response.SelectAsArray(RemoteFoldingRange.FromLspFoldingRange); + return result.Response.SelectAsArray(RemoteFoldingRange.FromVsFoldingRange); } internal TestAccessor GetTestAccessor() => new(this); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs index 0b3ca3eccc7..77504ae52e2 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs @@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.SemanticTokens; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs index 1461c58f588..1acfee411eb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSignatureHelpEndpoint.cs @@ -17,7 +17,9 @@ using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using Microsoft.VisualStudio.Razor.Settings; -using RLSP = Roslyn.LanguageServer.Protocol; +using static Roslyn.LanguageServer.Protocol.RoslynLspExtensions; +using RoslynLspFactory = Roslyn.LanguageServer.Protocol.RoslynLspFactory; +using RoslynSignatureHelp = Roslyn.LanguageServer.Protocol.SignatureHelp; namespace Microsoft.VisualStudio.LanguageServices.Razor.LanguageClient.Cohost; @@ -34,7 +36,7 @@ internal class CohostSignatureHelpEndpoint( IHtmlDocumentSynchronizer htmlDocumentSynchronizer, LSPRequestInvoker requestInvoker, ILoggerFactory loggerFactory) - : AbstractRazorCohostDocumentRequestHandler?>, IDynamicRegistrationProvider + : AbstractRazorCohostDocumentRequestHandler?>, IDynamicRegistrationProvider { private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker; private readonly IClientSettingsManager _clientSettingsManager = clientSettingsManager; @@ -69,10 +71,10 @@ internal class CohostSignatureHelpEndpoint( // NOTE: The use of SumType here is a little odd, but it allows us to return Roslyn LSP types from the Roslyn call, and VS LSP types from the Html // call. It works because both sets of types are attributed the right way, so the Json ends up looking the same and the client doesn't // care. Ideally eventually we will be able to move all of this to just Roslyn LSP types, but we might have to wait for Web Tools - protected override Task?> HandleRequestAsync(SignatureHelpParams request, RazorCohostRequestContext context, CancellationToken cancellationToken) + protected override Task?> HandleRequestAsync(SignatureHelpParams request, RazorCohostRequestContext context, CancellationToken cancellationToken) => HandleRequestAsync(request, context.TextDocument.AssumeNotNull(), cancellationToken); - private async Task?> HandleRequestAsync(SignatureHelpParams request, TextDocument razorDocument, CancellationToken cancellationToken) + private async Task?> HandleRequestAsync(SignatureHelpParams request, TextDocument razorDocument, CancellationToken cancellationToken) { // Return nothing if "Parameter Information" option is disabled unless signature help is invoked explicitly via command as opposed to typing or content change if (request.Context is { TriggerKind: not SignatureHelpTriggerKind.Invoked } && @@ -81,9 +83,10 @@ internal class CohostSignatureHelpEndpoint( return null; } - var data = await _remoteServiceInvoker.TryInvokeAsync( + var data = await _remoteServiceInvoker.TryInvokeAsync( razorDocument.Project.Solution, - (service, solutionInfo, cancellationToken) => service.GetSignatureHelpAsync(solutionInfo, razorDocument.Id, new RLSP.Position(request.Position.Line, request.Position.Character), cancellationToken), + (service, solutionInfo, cancellationToken) => + service.GetSignatureHelpAsync(solutionInfo, razorDocument.Id, RoslynLspFactory.CreatePosition(request.Position.ToLinePosition()), cancellationToken), cancellationToken) .ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs index 9dc498ad081..4582ca61358 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostUriPresentationEndpoint.cs @@ -65,9 +65,9 @@ internal class CohostUriPresentationEndpoint( private async Task HandleRequestAsync(VSInternalUriPresentationParams request, TextDocument razorDocument, CancellationToken cancellationToken) { var data = await _remoteServiceInvoker.TryInvokeAsync>( - razorDocument.Project.Solution, - (service, solutionInfo, cancellationToken) => service.GetPresentationAsync(solutionInfo, razorDocument.Id, request.Range.ToLinePositionSpan(), request.Uris, cancellationToken), - cancellationToken).ConfigureAwait(false); + razorDocument.Project.Solution, + (service, solutionInfo, cancellationToken) => service.GetPresentationAsync(solutionInfo, razorDocument.Id, request.Range.ToLinePositionSpan(), request.Uris, cancellationToken), + cancellationToken).ConfigureAwait(false); // If we got a response back, then we're good to go if (data.Result is { } textChange) @@ -84,7 +84,7 @@ internal class CohostUriPresentationEndpoint( { Uri = request.TextDocument.Uri }, - Edits = [textChange.ToTextEdit(sourceText)] + Edits = [sourceText.GetTextEdit(textChange)] } } }; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultLSPBreakpointSpanProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultLSPBreakpointSpanProvider.cs index 89c8291df75..ee9438b506f 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultLSPBreakpointSpanProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultLSPBreakpointSpanProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol.Debugging; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient.Debugging; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorBreakpointResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorBreakpointResolver.cs index c023c90c3b2..84dd82b1dea 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorBreakpointResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorBreakpointResolver.cs @@ -11,6 +11,7 @@ using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.Debugging; using Microsoft.VisualStudio.Text; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient.Debugging; @@ -95,8 +96,8 @@ public DefaultRazorBreakpointResolver( return cachedRange; } - var lspPosition = new Position(lineIndex, characterIndex); - var hostDocumentRange = await _breakpointSpanProvider.GetBreakpointSpanAsync(documentSnapshot, lspPosition, cancellationToken).ConfigureAwait(false); + var position = VsLspFactory.CreatePosition(lineIndex, characterIndex); + var hostDocumentRange = await _breakpointSpanProvider.GetBreakpointSpanAsync(documentSnapshot, position, cancellationToken).ConfigureAwait(false); if (hostDocumentRange is null) { // can't map the position, invalid breakpoint location. diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorProximityExpressionResolver.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorProximityExpressionResolver.cs index 66bbafbf8bf..1b129fef497 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorProximityExpressionResolver.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Debugging/DefaultRazorProximityExpressionResolver.cs @@ -95,7 +95,7 @@ public DefaultRazorProximityExpressionResolver( return cachedExpressions; } - var position = new Position(lineIndex, characterIndex); + var position = VsLspFactory.CreatePosition(lineIndex, characterIndex); var proximityExpressions = await _proximityExpressionsProvider.GetProximityExpressionsAsync(documentSnapshot, position, cancellationToken).ConfigureAwait(false); // Cache range so if we're asked again for this document/line/character we don't have to go async. diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProvider.cs index 2ace7bbf3a4..caca4cd081d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProvider.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentMapping; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient.DocumentMapping; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/LSPDocumentMappingProvider.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/LSPDocumentMappingProvider.cs index 5d486dd4eed..1adeb935106 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/LSPDocumentMappingProvider.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/DocumentMapping/LSPDocumentMappingProvider.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentMapping; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient.DocumentMapping; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs index fe14b8f494b..6f86ccd57dd 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; @@ -182,29 +181,22 @@ private void ConvertJsonElementToJObject(VSInternalCompletionList completionList private static TextEdit BuildRevertedEdit(TextEdit provisionalTextEdit) { TextEdit? revertedProvisionalTextEdit; - if (provisionalTextEdit.Range.Start == provisionalTextEdit.Range.End) + + var range = provisionalTextEdit.Range; + + if (range.Start == range.End) { // Insertion - revertedProvisionalTextEdit = new TextEdit() - { - Range = new Range() - { - Start = provisionalTextEdit.Range.Start, - - // We're making an assumption that provisional text edits do not span more than 1 line. - End = new Position(provisionalTextEdit.Range.End.Line, provisionalTextEdit.Range.End.Character + provisionalTextEdit.NewText.Length), - }, - NewText = string.Empty - }; + revertedProvisionalTextEdit = VsLspFactory.CreateTextEdit( + range: VsLspFactory.CreateSingleLineRange( + range.Start, + length: range.End.Character + provisionalTextEdit.NewText.Length), + newText: string.Empty); } else { // Replace - revertedProvisionalTextEdit = new TextEdit() - { - Range = provisionalTextEdit.Range, - NewText = string.Empty - }; + revertedProvisionalTextEdit = VsLspFactory.CreateTextEdit(range, string.Empty); } return revertedProvisionalTextEdit; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs index c7453791f98..0ac519a37af 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Diagnostics; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs index a33e9ff4c83..a9be7721d86 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_FoldingRange.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Folding; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.Extensions; using StreamJsonRpc; diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLSPSpanMappingService.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLSPSpanMappingService.cs index 9e988a8c9f7..5775f527c9c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLSPSpanMappingService.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/RazorLSPSpanMappingService.cs @@ -12,9 +12,9 @@ using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.DocumentMapping; using Microsoft.VisualStudio.Text; @@ -55,7 +55,7 @@ private async Task> MapSpansAsync( throw new ArgumentNullException(nameof(spans)); } - var projectedRanges = spans.Select(span => span.ToRange(sourceTextGenerated)).ToArray(); + var projectedRanges = spans.Select(sourceTextGenerated.GetRange).ToArray(); var mappedResult = await _lspDocumentMappingProvider.MapToDocumentRangesAsync( RazorLanguageKind.CSharp, @@ -77,12 +77,13 @@ internal static ImmutableArray GetMappedSpanResults( { if (mappedResult is null) { - return ImmutableArray.Empty; + return []; } - using var results = new PooledArrayBuilder(); + var ranges = mappedResult.Ranges; + using var results = new PooledArrayBuilder(capacity: ranges.Length); - foreach (var mappedRange in mappedResult.Ranges) + foreach (var mappedRange in ranges) { if (mappedRange.IsUndefined()) { @@ -91,8 +92,8 @@ internal static ImmutableArray GetMappedSpanResults( continue; } - var mappedSpan = mappedRange.AsTextSpan(sourceTextRazor); - var linePositionSpan = sourceTextRazor.Lines.GetLinePositionSpan(mappedSpan); + var mappedSpan = sourceTextRazor.GetTextSpan(mappedRange); + var linePositionSpan = sourceTextRazor.GetLinePositionSpan(mappedSpan); results.Add(new RazorMappedSpanResult(localFilePath, linePositionSpan, mappedSpan)); } diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Microsoft.VisualStudio.LanguageServices.Razor.csproj b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Microsoft.VisualStudio.LanguageServices.Razor.csproj index f9f38828e4b..97b62d4f4a8 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Microsoft.VisualStudio.LanguageServices.Razor.csproj +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Microsoft.VisualStudio.LanguageServices.Razor.csproj @@ -11,10 +11,6 @@ Microsoft.VisualStudio.Razor - - - - diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs index 62dfbe5e0c6..0e806675535 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/AutoClosingTagOnAutoInsertProviderTest.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Test.Common; -using Moq; using Xunit; using Xunit.Abstractions; using static Microsoft.AspNetCore.Razor.Language.CommonMetadata; @@ -952,7 +951,7 @@ internal override IOnAutoInsertProvider CreateProvider() var configService = StrictMock.Of(); var optionsMonitor = new RazorLSPOptionsMonitor(configService, Options); - var provider = new AutoClosingTagOnAutoInsertProvider(optionsMonitor, LoggerFactory); + var provider = new AutoClosingTagOnAutoInsertProvider(optionsMonitor); return provider; } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/CloseTextTagOnAutoInsertProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/CloseTextTagOnAutoInsertProviderTest.cs index 53d858846da..18fed07bd85 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/CloseTextTagOnAutoInsertProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/CloseTextTagOnAutoInsertProviderTest.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Test.Common; -using Moq; using Xunit; using Xunit.Abstractions; @@ -44,7 +43,7 @@ internal override IOnAutoInsertProvider CreateProvider() var configService = StrictMock.Of(); var optionsMonitor = new RazorLSPOptionsMonitor(configService, RazorLSPOptions.Default); - var provider = new CloseTextTagOnAutoInsertProvider(optionsMonitor, LoggerFactory); + var provider = new CloseTextTagOnAutoInsertProvider(optionsMonitor); return provider; } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.NetFx.cs index da3bb38772b..7f7e31e9747 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.NetFx.cs @@ -6,8 +6,8 @@ using Microsoft.AspNetCore.Razor.LanguageServer.Formatting; using Microsoft.AspNetCore.Razor.LanguageServer.Test; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; @@ -31,7 +31,7 @@ public async Task Handle_SingleProvider_InvokesProvider() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = ">", Options = new FormattingOptions { @@ -62,18 +62,18 @@ public async Task Handle_MultipleProviderSameTrigger_UsesSuccessful() var optionsMonitor = GetOptionsMonitor(); var insertProvider1 = new TestOnAutoInsertProvider(">", canResolve: false) { - ResolvedTextEdit = new TextEdit() + ResolvedTextEdit = VsLspFactory.CreateTextEdit(position: (0, 0), string.Empty) }; var insertProvider2 = new TestOnAutoInsertProvider(">", canResolve: true) { - ResolvedTextEdit = new TextEdit() + ResolvedTextEdit = VsLspFactory.CreateTextEdit(position: (0, 0), string.Empty) }; var formattingService = await TestRazorFormattingService.CreateWithFullSupportAsync(LoggerFactory); var endpoint = new OnAutoInsertEndpoint(LanguageServerFeatureOptions, DocumentMappingService, languageServer, [insertProvider1, insertProvider2], optionsMonitor, TestAdhocWorkspaceFactory.Instance, formattingService, LoggerFactory); var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = ">", Options = new FormattingOptions { @@ -107,18 +107,18 @@ public async Task Handle_MultipleProviderSameTrigger_UsesFirstSuccessful() var optionsMonitor = GetOptionsMonitor(); var insertProvider1 = new TestOnAutoInsertProvider(">", canResolve: true) { - ResolvedTextEdit = new TextEdit() + ResolvedTextEdit = VsLspFactory.CreateTextEdit(position: (0, 0), string.Empty) }; var insertProvider2 = new TestOnAutoInsertProvider(">", canResolve: true) { - ResolvedTextEdit = new TextEdit() + ResolvedTextEdit = VsLspFactory.CreateTextEdit(position: (0, 0), string.Empty) }; var formattingService = await TestRazorFormattingService.CreateWithFullSupportAsync(LoggerFactory); var endpoint = new OnAutoInsertEndpoint(LanguageServerFeatureOptions, DocumentMappingService, languageServer, [insertProvider1, insertProvider2], optionsMonitor, TestAdhocWorkspaceFactory.Instance, formattingService, LoggerFactory); var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = ">", Options = new FormattingOptions { @@ -155,7 +155,7 @@ public async Task Handle_NoApplicableProvider_CallsProviderAndReturnsNull() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = ">", Options = new FormattingOptions { @@ -190,7 +190,7 @@ public async Task Handle_OnTypeFormattingOff_Html_CallsLanguageServer() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = "=", Options = new FormattingOptions { @@ -223,7 +223,7 @@ public async Task Handle_AutoInsertAttributeQuotesOff_Html_DoesNotCallLanguageSe var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = "=", Options = new FormattingOptions { @@ -359,11 +359,11 @@ private async Task VerifyCSharpOnAutoInsertAsync(string input, string expected, var formattingService = await TestRazorFormattingService.CreateWithFullSupportAsync(LoggerFactory); var endpoint = new OnAutoInsertEndpoint(LanguageServerFeatureOptions, DocumentMappingService, languageServer, [insertProvider], optionsMonitor, TestAdhocWorkspaceFactory.Instance, formattingService, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); + var text = codeDocument.Source.Text; var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = new Uri(razorFilePath), }, - Position = new Position(line, offset), + Position = text.GetPosition(cursorPosition), Character = character, Options = new FormattingOptions { @@ -383,8 +383,8 @@ private async Task VerifyCSharpOnAutoInsertAsync(string input, string expected, Assert.False(insertProvider.Called); Assert.Equal(1, languageServer.RequestCount); - var edits = new[] { result.TextEdit.ToTextChange(codeDocument.GetSourceText()) }; - var newText = codeDocument.GetSourceText().WithChanges(edits).ToString(); + var edits = new[] { text.GetTextChange(result.TextEdit) }; + var newText = text.WithChanges(edits).ToString(); Assert.Equal(expected, newText); } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.cs index 80c74beef0e..57a48de76b4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/OnAutoInsertEndpointTest.cs @@ -31,7 +31,7 @@ public async Task Handle_MultipleProviderUnmatchingTrigger_ReturnsNull() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = "!", Options = new FormattingOptions { @@ -66,7 +66,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = ">", Options = new FormattingOptions { @@ -101,7 +101,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, Character = ">", Options = new FormattingOptions { @@ -135,7 +135,7 @@ public async Task Handle_OnTypeFormattingOff_CSharp_ReturnsNull() var @params = new VSInternalDocumentOnAutoInsertParams() { TextDocument = new TextDocumentIdentifier { Uri = uri, }, - Position = new Position(1, 3), + Position = VsLspFactory.CreatePosition(1, 3), Character = "/", Options = new FormattingOptions { diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionInfoStrategyTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionInfoStrategyTest.cs index 4e7e28c9ccd..5b72597e19c 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionInfoStrategyTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/PreferHtmlInAttributeValuesDocumentPositionInfoStrategyTest.cs @@ -2,12 +2,11 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.AutoInsert; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using Xunit.Abstractions; @@ -44,14 +43,14 @@ internal async Task TryGetPositionInfoAsync_AtVariousPosition_ReturnsCorrectLang TestFileMarkupParser.GetPosition(documentText, out documentText, out var cursorPosition); var razorFilePath = "file://path/test.razor"; var codeDocument = CreateCodeDocument(documentText, filePath: razorFilePath); - codeDocument.Source.Text.GetLineAndOffset(cursorPosition, out var line, out var offset); - var position = new Position(line, offset); + var position = codeDocument.Source.Text.GetPosition(cursorPosition); var uri = new Uri(razorFilePath); _ = await CreateLanguageServerAsync(codeDocument, razorFilePath); var documentContext = CreateDocumentContext(uri, codeDocument); // Act - var result = await PreferHtmlInAttributeValuesDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync(DocumentMappingService, documentContext, position, Logger, CancellationToken.None); + var result = await PreferHtmlInAttributeValuesDocumentPositionInfoStrategy.Instance.TryGetPositionInfoAsync( + DocumentMappingService, documentContext, position, DisposalToken); // Assert Assert.NotNull(result); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs index 82613a45ca5..cef29ea2d43 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/AutoInsert/RazorOnAutoInsertProviderTestBase.cs @@ -35,8 +35,7 @@ protected void RunAutoInsertTest(string input, string expected, int tabSize = 4, TestFileMarkupParser.GetPosition(input, out input, out var location); var source = SourceText.From(input); - source.GetLineAndOffset(location, out var line, out var column); - var position = new Position(line, column); + var position = source.GetPosition(location); var path = "file:///path/to/document.razor"; var uri = new Uri(path); @@ -64,7 +63,7 @@ protected void RunAutoInsertTest(string input, string expected, int tabSize = 4, private static SourceText ApplyEdit(SourceText source, TextEdit edit) { - var change = edit.ToTextChange(source); + var change = source.GetTextChange(edit); return source.WithChanges(change); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs index 5a1a0a6d6ee..7d22fc8ee82 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/AddUsingsCodeActionResolverTest.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionProviderTest.cs index 08e9082c0d7..335e5df5f48 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionProviderTest.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -53,7 +52,7 @@ public async Task ProvideAsync_ValidCodeActions_ReturnsProvidedCodeAction() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -84,7 +83,7 @@ public async Task ProvideAsync_SupportsCodeActionResolveFalse_ValidCodeActions_R var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -112,7 +111,7 @@ public async Task ProvideAsync_FunctionsBlock_SingleLine_ValidCodeActions_Return var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -145,7 +144,7 @@ public async Task ProvideAsync_FunctionsBlock_OpenBraceSameLine_ValidCodeActions var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -179,7 +178,7 @@ public async Task ProvideAsync_FunctionsBlock_OpenBraceNextLine_ValidCodeActions var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -210,7 +209,7 @@ public async Task ProvideAsync_InvalidCodeActions_ReturnsNoCodeActions() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -247,7 +246,7 @@ public async Task ProvideAsync_InvalidCodeActions_ShowAllFeatureFlagOn_ReturnsCo var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -293,7 +292,7 @@ public async Task ProvideAsync_ImplicitExpression_ReturnsProvidedCodeAction() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -335,7 +334,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var documentSnapshot = Mock.Of(document => document.GetGeneratedOutputAsync() == Task.FromResult(codeDocument) && - document.GetTextAsync() == Task.FromResult(codeDocument.GetSourceText()) && + document.GetTextAsync() == Task.FromResult(codeDocument.Source.Text) && document.Project.GetTagHelpersAsync(It.IsAny()) == new ValueTask>(tagHelpers), MockBehavior.Strict); var sourceText = SourceText.From(text); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs index 254bdf1b91c..6062be141b2 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/DefaultCSharpCodeActionResolverTest.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using System.Text.Json; -using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Razor.Extensions; @@ -16,7 +15,6 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; @@ -33,26 +31,15 @@ public class DefaultCSharpCodeActionResolverTest(ITestOutputHelper testOutput) : Edit = new WorkspaceEdit() { DocumentChanges = new TextDocumentEdit[] { - new TextDocumentEdit() + new() { - Edits = [ - new TextEdit() - { - NewText = "Generated C# Based Edit" - } - ] + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), "Generated C# Based Edit")] } } } }; - private static readonly TextEdit[] s_defaultFormattedEdits = - [ - new TextEdit() - { - NewText = "Remapped & Formatted Edit" - } - ]; + private static readonly TextEdit[] s_defaultFormattedEdits = [VsLspFactory.CreateTextEdit(position: (0, 0), "Remapped & Formatted Edit")]; private static readonly CodeAction s_defaultUnresolvedCodeAction = new CodeAction() { @@ -114,26 +101,17 @@ public async Task ResolveAsync_MultipleDocumentChanges_ReturnsOriginalCodeAction Data = JsonSerializer.SerializeToElement(new object()), Edit = new WorkspaceEdit() { - DocumentChanges = new TextDocumentEdit[] { - new TextDocumentEdit() - { - Edits = new TextEdit[] { - new TextEdit() - { - NewText = "1. Generated C# Based Edit" - } - } - }, - new TextDocumentEdit() - { - Edits = new TextEdit[] { - new TextEdit() - { - NewText = "2. Generated C# Based Edit" - } - } - } + DocumentChanges = new TextDocumentEdit[] + { + new TextDocumentEdit() + { + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), "1. Generated C# Based Edit")] + }, + new TextDocumentEdit() + { + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), "2. Generated C# Based Edit")] } + } } }; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs index 6d433efb738..7c3c0afff5d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CSharp/TypeAccessibilityCodeActionProviderTest.cs @@ -15,7 +15,6 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; @@ -35,7 +34,7 @@ public async Task Handle_MissingDiagnostics_ReturnsEmpty() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { // Even though the DTO declares this as non-null, we want to make sure we behave @@ -72,7 +71,7 @@ public async Task Handle_InvalidDiagnostics_VSCode_ReturnsEmpty() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { Diagnostics = new Diagnostic[] { @@ -116,7 +115,6 @@ public async Task Handle_InvalidDiagnostics_VSCode_ReturnsEmpty() // Assert Assert.Empty(results); - } [Fact] @@ -128,7 +126,7 @@ public async Task Handle_EmptyCodeActions_ReturnsEmpty() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { Diagnostics = new Diagnostic[] { @@ -168,7 +166,7 @@ public async Task Handle_ValidDiagnostic_ValidCodeAction_VSCode_ReturnsCodeActio var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { Diagnostics = new Diagnostic[] { @@ -181,10 +179,7 @@ public async Task Handle_ValidDiagnostic_ValidCodeAction_VSCode_ReturnsCodeActio { Severity = DiagnosticSeverity.Error, Code = errorCode, - Range = new Range{ - Start = new Position(0, 8), - End = new Position(0, 12), - } + Range = VsLspFactory.CreateRange(0, 8, 0, 12) }, new Diagnostic() { @@ -219,7 +214,7 @@ public async Task Handle_ValidDiagnostic_ValidCodeAction_VSCode_ReturnsCodeActio // Assert Assert.Collection(results, - r => + r => { Assert.Equal("@using System.IO", r.Title); Assert.Null(r.Edit); @@ -247,7 +242,7 @@ public async Task Handle_CodeActionInSingleLineDirective_VS_ReturnsOnlyUsingCode var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { Diagnostics = Array.Empty() @@ -299,7 +294,7 @@ public async Task Handle_ValidCodeAction_VS_ReturnsCodeActions() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { Diagnostics = Array.Empty() @@ -357,7 +352,7 @@ public async Task Handle_ValidDiagnostic_MultipleValidCodeActions_VSCode_Returns var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() { Diagnostics = new Diagnostic[] { @@ -370,10 +365,7 @@ public async Task Handle_ValidDiagnostic_MultipleValidCodeActions_VSCode_Returns { Severity = DiagnosticSeverity.Error, Code = "CS0246", - Range = new Range{ - Start = new Position(0, 8), - End = new Position(0, 12) - } + Range = VsLspFactory.CreateRange(0, 8, 0, 12) }, new Diagnostic() { @@ -468,12 +460,12 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var cSharpDocument = codeDocument.GetCSharpDocument(); var diagnosticDescriptor = new RazorDiagnosticDescriptor("RZ10012", "diagnostic", RazorDiagnosticSeverity.Error); var diagnostic = RazorDiagnostic.Create(diagnosticDescriptor, componentSourceSpan); - var cSharpDocumentWithDiagnostic = RazorCSharpDocument.Create(codeDocument, cSharpDocument.GeneratedCode, cSharpDocument.Options, new[] { diagnostic }); + var cSharpDocumentWithDiagnostic = RazorCSharpDocument.Create(codeDocument, cSharpDocument.GeneratedCode, cSharpDocument.Options, [diagnostic]); codeDocument.SetCSharpDocument(cSharpDocumentWithDiagnostic); var documentSnapshot = Mock.Of(document => document.GetGeneratedOutputAsync() == Task.FromResult(codeDocument) && - document.GetTextAsync() == Task.FromResult(codeDocument.GetSourceText()) && + document.GetTextAsync() == Task.FromResult(codeDocument.Source.Text) && document.Project.GetTagHelpersAsync(It.IsAny()) == new ValueTask>(tagHelpers), MockBehavior.Strict); var sourceText = SourceText.From(text); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs index 664ce6c61bf..2196a72ccfa 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndToEndTest.NetFx.cs @@ -701,7 +701,7 @@ public async Task Handle_GenerateMethod_SetEventParameter_DoesNothing(string par TestFileMarkupParser.GetSpan(input, out input, out var textSpan); var razorFilePath = "file://C:/path/test.razor"; var codeDocument = CreateCodeDocument(input, filePath: razorFilePath); - var razorSourceText = codeDocument.GetSourceText(); + var razorSourceText = codeDocument.Source.Text; var uri = new Uri(razorFilePath); var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath); var documentContext = CreateDocumentContext(uri, codeDocument); @@ -740,7 +740,7 @@ public void Exists() TestFileMarkupParser.GetSpan(input, out input, out var textSpan); var razorFilePath = "file://C:/path/test.razor"; var codeDocument = CreateCodeDocument(input, filePath: razorFilePath); - var razorSourceText = codeDocument.GetSourceText(); + var razorSourceText = codeDocument.Source.Text; var uri = new Uri(razorFilePath); var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath); var documentContext = CreateDocumentContext(uri, codeDocument); @@ -1021,7 +1021,7 @@ private async Task ValidateCodeBehindFileAsync( TestFileMarkupParser.GetSpan(input, out input, out var textSpan); var codeDocument = CreateCodeDocument(input, filePath: razorFilePath, rootNamespace: "Test"); - var razorSourceText = codeDocument.GetSourceText(); + var razorSourceText = codeDocument.Source.Text; var uri = new Uri(razorFilePath); var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath); var documentContext = CreateDocumentContext(uri, codeDocument); @@ -1059,11 +1059,11 @@ private async Task ValidateCodeBehindFileAsync( { if (FilePathNormalizer.Normalize(change.TextDocument.Uri.GetAbsoluteOrUNCPath()) == codeBehindFilePath) { - codeBehindEdits.AddRange(change.Edits.Select(e => e.ToTextChange(codeBehindSourceText))); + codeBehindEdits.AddRange(change.Edits.Select(codeBehindSourceText.GetTextChange)); } else { - razorEdits.AddRange(change.Edits.Select(e => e.ToTextChange(razorSourceText))); + razorEdits.AddRange(change.Edits.Select(razorSourceText.GetTextChange)); } } @@ -1105,7 +1105,7 @@ private async Task ValidateCodeActionAsync( var razorFilePath = "C:/path/test.razor"; var codeDocument = CreateCodeDocument(input, filePath: razorFilePath); - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var uri = new Uri(razorFilePath); var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath); var documentContext = CreateDocumentContext(uri, codeDocument); @@ -1141,7 +1141,7 @@ private async Task ValidateCodeActionAsync( var edits = new List(); foreach (var change in changes) { - edits.AddRange(change.Edits.Select(e => e.ToTextChange(sourceText))); + edits.AddRange(change.Edits.Select(sourceText.GetTextChange)); } var actual = sourceText.WithChanges(edits).ToString(); @@ -1197,7 +1197,7 @@ private async Task[]> GetCodeActionsAsync( var @params = new VSCodeActionParams { TextDocument = new VSTextDocumentIdentifier { Uri = uri }, - Range = textSpan.ToRange(sourceText), + Range = sourceText.GetRange(textSpan), Context = new VSInternalCodeActionContext() { Diagnostics = diagnostics ?? [] } }; @@ -1264,7 +1264,7 @@ public override bool TryCreate( } var projectWorkspaceState = ProjectWorkspaceState.Create(_tagHelperDescriptors.ToImmutableArray()); - var testDocumentSnapshot = TestDocumentSnapshot.Create(FilePath, CodeDocument.GetSourceText().ToString(), CodeAnalysis.VersionStamp.Default, projectWorkspaceState); + var testDocumentSnapshot = TestDocumentSnapshot.Create(FilePath, CodeDocument.Source.Text.ToString(), CodeAnalysis.VersionStamp.Default, projectWorkspaceState); testDocumentSnapshot.With(CodeDocument); context = CreateDocumentContext(new Uri(FilePath), testDocumentSnapshot); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs index f032719c971..e5dc42a3fb7 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/CodeActionEndpointTest.cs @@ -72,7 +72,7 @@ public async Task Handle_NoDocument() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; @@ -108,7 +108,7 @@ public async Task Handle_UnsupportedDocument() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -142,7 +142,7 @@ public async Task Handle_NoProviders() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -179,7 +179,7 @@ public async Task Handle_OneRazorCodeActionProvider() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -219,7 +219,7 @@ public async Task Handle_OneCSharpCodeActionProvider() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -257,7 +257,7 @@ public async Task Handle_OneCodeActionProviderWithMultipleCodeActions() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -302,7 +302,7 @@ public async Task Handle_MultipleCodeActionProvidersWithMultipleCodeActions() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -347,7 +347,7 @@ public async Task Handle_MultipleProviders() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -385,7 +385,7 @@ public async Task Handle_OneNullReturningProvider() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -430,7 +430,7 @@ public async Task Handle_MultipleMixedProvider() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -470,7 +470,7 @@ public async Task Handle_MultipleMixedProvider_SupportsCodeActionResolveTrue() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -522,7 +522,7 @@ public async Task Handle_MixedProvider_SupportsCodeActionResolveTrue_UsesGroups( var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -574,7 +574,7 @@ public async Task Handle_MultipleMixedProvider_SupportsCodeActionResolveFalse() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; var requestContext = CreateRazorRequestContext(documentContext); @@ -619,8 +619,8 @@ public async Task GenerateRazorCodeActionContextAsync_WithSelectionRange() _supportsCodeActionResolve = false }; - var initialRange = new Range { Start = new Position(0, 1), End = new Position(0, 1) }; - var selectionRange = new Range { Start = new Position(0, 5), End = new Position(0, 5) }; + var initialRange = VsLspFactory.CreateZeroWidthRange(0, 1); + var selectionRange = VsLspFactory.CreateZeroWidthRange(0, 5); var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, @@ -661,7 +661,7 @@ public async Task GenerateRazorCodeActionContextAsync_WithoutSelectionRange() _supportsCodeActionResolve = false }; - var initialRange = new Range { Start = new Position(0, 1), End = new Position(0, 1) }; + var initialRange = VsLspFactory.CreateZeroWidthRange(0, 1); var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, @@ -706,7 +706,7 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_InvalidRangeMappin _supportsCodeActionResolve = false }; - var initialRange = new Range { Start = new Position(0, 1), End = new Position(0, 1) }; + var initialRange = VsLspFactory.CreateZeroWidthRange(0, 1); var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, @@ -732,7 +732,7 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_ReturnsCodeActions var documentPath = new Uri("C:/path/to/Page.razor"); var codeDocument = CreateCodeDocument("@code {}"); var documentContext = CreateDocumentContext(documentPath, codeDocument); - var projectedRange = new Range { Start = new Position(15, 2), End = new Position(15, 2) }; + var projectedRange = VsLspFactory.CreateZeroWidthRange(15, 2); var documentMappingService = CreateDocumentMappingService(projectedRange.ToLinePositionSpan()); var languageServer = CreateLanguageServer(); var codeActionEndpoint = new CodeActionEndpoint( @@ -750,7 +750,7 @@ public async Task GetCSharpCodeActionsFromLanguageServerAsync_ReturnsCodeActions _supportsCodeActionResolve = false }; - var initialRange = new Range { Start = new Position(0, 1), End = new Position(0, 1) }; + var initialRange = VsLspFactory.CreateZeroWidthRange(0, 1); var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = documentPath }, diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs index 252fbe34eb0..5104d53b0fa 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionProviderTest.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -35,7 +34,7 @@ public async Task ProvideAsync_WrapsResolvableCodeActions() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -68,7 +67,7 @@ public async Task ProvideAsync_RemapsAndFixesEdits() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -80,13 +79,13 @@ public async Task ProvideAsync_RemapsAndFixesEdits() { DocumentChanges = new TextDocumentEdit[] { - new TextDocumentEdit - { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri= new Uri(documentPath), Version = 1 }, - Edits = new TextEdit[] + new() { + TextDocument = new OptionalVersionedTextDocumentIdentifier { - new TextEdit { NewText = "Goo ~~~~~~~~~~~~~~~ Bar", Range = span.ToRange(context.SourceText) } - } + Uri = new Uri(documentPath), + Version = 1 + }, + Edits = [VsLspFactory.CreateTextEdit(context.SourceText.GetRange(span), "Goo ~~~~~~~~~~~~~~~ Bar")] } } }; @@ -107,13 +106,13 @@ public async Task ProvideAsync_RemapsAndFixesEdits() { DocumentChanges = new TextDocumentEdit[] { - new TextDocumentEdit - { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri= new Uri("c:/Test.razor.html"), Version = 1 }, - Edits = new TextEdit[] + new() { + TextDocument = new OptionalVersionedTextDocumentIdentifier { - new TextEdit { NewText = "Goo" } - } + Uri = new Uri("c:/Test.razor.html"), + Version = 1 + }, + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), "Goo")] } } } @@ -155,7 +154,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext( var documentSnapshot = Mock.Of(document => document.GetGeneratedOutputAsync() == Task.FromResult(codeDocument) && - document.GetTextAsync() == Task.FromResult(codeDocument.GetSourceText()) && + document.GetTextAsync() == Task.FromResult(codeDocument.Source.Text) && document.Project.GetTagHelpersAsync(It.IsAny()) == new ValueTask>(tagHelpers), MockBehavior.Strict); var sourceText = SourceText.From(text); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs index 28e7aab6e3d..5d7704aa426 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Html/DefaultHtmlCodeActionResolverTest.cs @@ -3,7 +3,6 @@ using System; using System.Text.Json; -using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.CodeActions.Models; @@ -15,6 +14,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; @@ -39,14 +39,14 @@ public async Task ResolveAsync_RemapsAndFixesEdits() var remappedEdit = new WorkspaceEdit { DocumentChanges = new TextDocumentEdit[] - { - new TextDocumentEdit - { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri= documentUri, Version = 1 }, - Edits = new TextEdit[] + { + new() { + TextDocument = new OptionalVersionedTextDocumentIdentifier { - new TextEdit { NewText = "Goo ~~~~~~~~~~~~~~~ Bar", Range = span.ToRange(sourceText) } - } + Uri = documentUri, + Version = 1 + }, + Edits = [VsLspFactory.CreateTextEdit(sourceText.GetRange(span), "Goo ~~~~~~~~~~~~~~~ Bar")] } } }; @@ -70,13 +70,14 @@ public async Task ResolveAsync_RemapsAndFixesEdits() { DocumentChanges = new TextDocumentEdit[] { - new TextDocumentEdit + new() { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri= new Uri("c:/Test.razor.html"), Version = 1 }, - Edits = new TextEdit[] + TextDocument = new OptionalVersionedTextDocumentIdentifier { - new TextEdit { NewText = "Goo" } - } + Uri = new Uri("c:/Test.razor.html"), + Version = 1 + }, + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), "Goo")] } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs index e0f94799c57..7d4ca269ff6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ComponentAccessibilityCodeActionProviderTest.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -36,7 +35,7 @@ public async Task Handle_NoTagName_DoesNotProvideLightBulb() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 1), End = new Position(0, 1), }, + Range = VsLspFactory.CreateZeroWidthRange(0, 1), Context = new VSInternalCodeActionContext() }; @@ -65,7 +64,7 @@ public async Task Handle_InvalidSyntaxTree_NoStartNode() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -95,7 +94,7 @@ public async Task Handle_CursorOutsideComponent() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -124,7 +123,7 @@ public async Task Handle_ExistingComponent_SupportsFileCreationTrue_ReturnsResul var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -172,7 +171,7 @@ public async Task Handle_ExistingComponent_CaseIncorrect_ReturnsResults() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -222,7 +221,7 @@ @using Fully.Qualified var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -264,7 +263,7 @@ public async Task Handle_ExistingGenericComponent_SupportsFileCreationTrue_Retur var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -312,7 +311,7 @@ public async Task Handle_NewComponent_SupportsFileCreationTrue_ReturnsResult() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -343,7 +342,7 @@ public async Task Handle_NewComponent_CaretInAttribute_ReturnsResult() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -374,7 +373,7 @@ public async Task Handle_NewComponent_SupportsFileCreationFalse_ReturnsEmpty() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -403,7 +402,7 @@ public async Task Handle_ExistingComponent_SupportsFileCreationFalse_ReturnsResu var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range { Start = new Position(0, 0), End = new Position(0, 0) }, + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -466,7 +465,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext(VSCodeActionP var documentSnapshot = Mock.Of(document => document.GetGeneratedOutputAsync() == Task.FromResult(codeDocument) && - document.GetTextAsync() == Task.FromResult(codeDocument.GetSourceText()) && + document.GetTextAsync() == Task.FromResult(codeDocument.Source.Text) && document.Project.GetTagHelpersAsync(It.IsAny()) == new ValueTask>(tagHelpers), MockBehavior.Strict); var sourceText = SourceText.From(text); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs index f8477ef3335..f44e40ddd6f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/CreateComponentCodeActionResolverTest.cs @@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs index 51f71904390..a0995f885a9 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionProviderTest.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -39,7 +38,7 @@ public async Task Handle_InvalidFileKind() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -70,7 +69,7 @@ public async Task Handle_OutsideCodeDirective() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -100,7 +99,7 @@ public async Task Handle_InCodeDirectiveBlock_ReturnsNull() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -130,7 +129,7 @@ public async Task Handle_InCodeDirectiveMalformed_ReturnsNull() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -165,7 +164,7 @@ void Test() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -206,7 +205,7 @@ public async Task Handle_InCodeDirective_SupportsFileCreationTrue_ReturnsResult( var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -249,7 +248,7 @@ public async Task Handle_AtEndOfCodeDirectiveWithNoSpace_ReturnsResult() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -286,7 +285,7 @@ public async Task Handle_InCodeDirective_SupportsFileCreationFalse_ReturnsNull() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -322,7 +321,7 @@ public async Task Handle_InFunctionsDirective_SupportsFileCreationTrue_ReturnsRe var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() }; @@ -359,7 +358,7 @@ public async Task Handle_NullRelativePath_ReturnsNull() var request = new VSCodeActionParams() { TextDocument = new VSTextDocumentIdentifier { Uri = new Uri(documentPath) }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = null! }; @@ -398,7 +397,7 @@ private static RazorCodeActionContext CreateRazorCodeActionContext(VSCodeActionP var documentSnapshot = Mock.Of(document => document.GetGeneratedOutputAsync() == Task.FromResult(codeDocument) && - document.GetTextAsync() == Task.FromResult(codeDocument.GetSourceText()), MockBehavior.Strict); + document.GetTextAsync() == Task.FromResult(codeDocument.Source.Text), MockBehavior.Strict); var sourceText = SourceText.From(text); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs index 0c2156c1071..5b3fce18457 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/CodeActions/Razor/ExtractToCodeBehindCodeActionResolverTest.cs @@ -14,7 +14,8 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -126,24 +127,25 @@ public async Task Handle_ExtractCodeBlock() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -188,24 +190,25 @@ public async Task Handle_ExtractCodeBlock2() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -258,24 +261,25 @@ private void M() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -338,24 +342,25 @@ private void M() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -420,24 +425,25 @@ private void M() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -490,24 +496,25 @@ public async Task Handle_ExtractFunctionsBlock() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var editCodeDocument)); - var editCodeDocumentEdit = editCodeDocument!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = editCodeDocument.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var editCodeBehind)); - var editCodeBehindEdit = editCodeBehind!.Edits.First(); + var editCodeBehindEdit = editCodeBehind.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -552,8 +559,8 @@ @using System.Diagnostics // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; @@ -561,15 +568,16 @@ @using System.Diagnostics var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var editCodeDocument)); - var editCodeDocumentEdit = editCodeDocument!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = editCodeDocument.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var editCodeBehind)); - var editCodeBehindEdit = editCodeBehind!.Edits.First(); + var editCodeBehindEdit = editCodeBehind.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -616,24 +624,25 @@ public async Task Handle_ExtractCodeBlockWithDirectives() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" using System; @@ -684,24 +693,25 @@ public async Task Handle_ExtractCodeBlock_CallsRoslyn() // Assert Assert.NotNull(workspaceEdit); - Assert.NotNull(workspaceEdit!.DocumentChanges); - Assert.Equal(3, workspaceEdit.DocumentChanges!.Value.Count()); + Assert.NotNull(workspaceEdit.DocumentChanges); + Assert.Equal(3, workspaceEdit.DocumentChanges.Value.Count()); - var documentChanges = workspaceEdit.DocumentChanges!.Value.ToArray(); + var documentChanges = workspaceEdit.DocumentChanges.Value.ToArray(); var createFileChange = documentChanges[0]; Assert.True(createFileChange.TryGetSecond(out var _)); var editCodeDocumentChange = documentChanges[1]; Assert.True(editCodeDocumentChange.TryGetFirst(out var textDocumentEdit1)); - var editCodeDocumentEdit = textDocumentEdit1!.Edits.First(); - Assert.True(editCodeDocumentEdit.Range.Start.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeStart)); + var editCodeDocumentEdit = textDocumentEdit1.Edits.First(); + var sourceText = codeDocument.Source.Text; + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.Start, out var removeStart)); Assert.Equal(actionParams.RemoveStart, removeStart); - Assert.True(editCodeDocumentEdit.Range.End.TryGetAbsoluteIndex(codeDocument.GetSourceText(), Logger, out var removeEnd)); + Assert.True(sourceText.TryGetAbsoluteIndex(editCodeDocumentEdit.Range.End, out var removeEnd)); Assert.Equal(actionParams.RemoveEnd, removeEnd); var editCodeBehindChange = documentChanges[2]; Assert.True(editCodeBehindChange.TryGetFirst(out var textDocumentEdit2)); - var editCodeBehindEdit = textDocumentEdit2!.Edits.First(); + var editCodeBehindEdit = textDocumentEdit2.Edits.First(); AssertEx.EqualOrDiff(""" Hi there! I'm from Roslyn diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs index 6dccf80a8ec..b39900715b0 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionItemResolverTest.NetFx.cs @@ -15,7 +15,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.Mef; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -53,8 +52,8 @@ public DelegatedCompletionItemResolverTest(ITestOutputHelper testOutput) }; var documentContext = TestDocumentContext.From("C:/path/to/file.cshtml", hostDocumentVersion: 0); - _csharpCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, new Position(10, 6), RazorLanguageKind.CSharp, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); - _htmlCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, new Position(0, 0), RazorLanguageKind.Html, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); + _csharpCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, VsLspFactory.CreatePosition(10, 6), RazorLanguageKind.CSharp, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); + _htmlCompletionParams = new DelegatedCompletionParams(documentContext.Identifier, VsLspFactory.DefaultPosition, RazorLanguageKind.Html, new VSInternalCompletionContext(), ProvisionalTextEdit: null, ShouldIncludeSnippets: false, CorrelationId: Guid.Empty); _documentContextFactory = new TestDocumentContextFactory(); _formattingService = new AsyncLazy(() => TestRazorFormattingService.CreateWithFullSupportAsync(LoggerFactory)); } @@ -174,7 +173,7 @@ async Task FooAsync() var resolvedItem = await ResolveCompletionItemAsync(input, itemToResolve: "await", DisposalToken); // Assert - var textChange = resolvedItem.TextEdit.Value.First.ToTextChange(originalSourceText); + var textChange = originalSourceText.GetTextChange(resolvedItem.TextEdit.Value.First); var actualSourceText = originalSourceText.WithChanges(textChange); Assert.True(expectedSourceText.ContentEquals(actualSourceText)); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs index 23fc20ed552..cc82c40eb4d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/DelegatedCompletionListProviderTest.cs @@ -7,12 +7,12 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.Mef; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -71,7 +71,7 @@ await _provider.GetCompletionListAsync( var delegatedParameters = _provider.DelegatedParams; Assert.NotNull(delegatedParameters); Assert.Equal(RazorLanguageKind.Html, delegatedParameters.ProjectedKind); - Assert.Equal(new Position(0, 1), delegatedParameters.ProjectedPosition); + Assert.Equal(VsLspFactory.CreatePosition(0, 1), delegatedParameters.ProjectedPosition); Assert.Equal(CompletionTriggerKind.Invoked, delegatedParameters.Context.TriggerKind); Assert.Equal(1337, delegatedParameters.Identifier.Version); Assert.Null(delegatedParameters.ProvisionalTextEdit); @@ -98,7 +98,7 @@ await _provider.GetCompletionListAsync( var delegatedParameters = _provider.DelegatedParams; Assert.NotNull(delegatedParameters); Assert.Equal(RazorLanguageKind.Html, delegatedParameters.ProjectedKind); - Assert.Equal(new Position(0, 1), delegatedParameters.ProjectedPosition); + Assert.Equal(VsLspFactory.CreatePosition(0, 1), delegatedParameters.ProjectedPosition); Assert.Equal(CompletionTriggerKind.TriggerCharacter, delegatedParameters.Context.TriggerKind); Assert.Equal(VSInternalCompletionInvokeKind.Typing, delegatedParameters.Context.InvokeKind); Assert.Equal(1337, delegatedParameters.Identifier.Version); @@ -126,7 +126,7 @@ await _provider.GetCompletionListAsync( var delegatedParameters = _provider.DelegatedParams; Assert.NotNull(delegatedParameters); Assert.Equal(RazorLanguageKind.Html, delegatedParameters.ProjectedKind); - Assert.Equal(new Position(0, 1), delegatedParameters.ProjectedPosition); + Assert.Equal(VsLspFactory.CreatePosition(0, 1), delegatedParameters.ProjectedPosition); Assert.Equal(CompletionTriggerKind.Invoked, delegatedParameters.Context.TriggerKind); Assert.Equal(VSInternalCompletionInvokeKind.Typing, delegatedParameters.Context.InvokeKind); Assert.Equal(1337, delegatedParameters.Identifier.Version); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TextEditResponseRewriterTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TextEditResponseRewriterTest.cs index dbbea3ab241..38115319260 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TextEditResponseRewriterTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/Delegation/TextEditResponseRewriterTest.cs @@ -19,11 +19,7 @@ public async Task RewriteAsync_NotCSharp_Noops() // Arrange var getCompletionsAt = 1; var documentContent = "<"; - var textEditRange = new Range() - { - Start = new Position(0, 0), - End = new Position(0, 1), - }; + var textEditRange = VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 1); var delegatedCompletionList = GenerateCompletionList(textEditRange); // Act @@ -40,18 +36,10 @@ public async Task RewriteAsync_CSharp_AdjustsItemRange() // Arrange var getCompletionsAt = 1; var documentContent = "@DateTime"; - var textEditRange = new Range() - { - // Line 19: __o = DateTime - Start = new Position(19, 6), - End = new Position(19, 14), - }; + // Line 19: __o = DateTime + var textEditRange = VsLspFactory.CreateSingleLineRange(line: 19, character: 6, length: 8); var delegatedCompletionList = GenerateCompletionList(textEditRange); - var expectedRange = new Range() - { - Start = new Position(0, 1), - End = new Position(0, 9), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 8); // Act var rewrittenCompletionList = await GetRewrittenCompletionListAsync( @@ -67,22 +55,14 @@ public async Task RewriteAsync_CSharp_AdjustsListRange() // Arrange var getCompletionsAt = 1; var documentContent = "@DateTime"; - var textEditRange = new Range() - { - // Line 19: __o = DateTime - Start = new Position(19, 6), - End = new Position(19, 14), - }; + // Line 19: __o = DateTime + var textEditRange = VsLspFactory.CreateSingleLineRange(line: 19, character: 6, length: 8); var delegatedCompletionList = GenerateCompletionList(textEditRange); delegatedCompletionList.ItemDefaults = new CompletionListItemDefaults() { EditRange = textEditRange, }; - var expectedRange = new Range() - { - Start = new Position(0, 1), - End = new Position(0, 9), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 8); // Act var rewrittenCompletionList = await GetRewrittenCompletionListAsync( @@ -96,17 +76,12 @@ private static VSInternalCompletionList GenerateCompletionList(Range textEditRan { return new VSInternalCompletionList() { - Items = new[] - { + Items = [ new VSInternalCompletionItem() { - TextEdit = new TextEdit() - { - NewText = "Hello", - Range = textEditRange, - } + TextEdit = VsLspFactory.CreateTextEdit(textEditRange, "Hello") } - } + ] }; } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs index cb5c9626d86..62edca4716a 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/DirectiveAttributeTransitionCompletionItemProviderTest.cs @@ -5,9 +5,9 @@ using System; using Microsoft.AspNetCore.Razor.Language; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs index 22ffe392c98..02c27f18395 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/MarkupTransitionCompletionItemProviderTest.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Legacy; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/RazorCompletionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/RazorCompletionEndpointTest.cs index 3bcf08b51d2..4809ad880ae 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/RazorCompletionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/RazorCompletionEndpointTest.cs @@ -21,14 +21,14 @@ public async Task Handle_NoDocumentContext_NoCompletionItems() // Arrange var documentPath = "C:/path/to/document.cshtml"; var optionsMonitor = GetOptionsMonitor(); - var completionEndpoint = new RazorCompletionEndpoint(completionListProvider: null, telemetryReporter: null, optionsMonitor, LoggerFactory); + var completionEndpoint = new RazorCompletionEndpoint(completionListProvider: null, telemetryReporter: null, optionsMonitor); var request = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = new Uri(documentPath) }, - Position = new Position(0, 1), + Position = VsLspFactory.CreatePosition(0, 1), Context = new VSInternalCompletionContext(), }; var requestContext = CreateRazorRequestContext(documentContext: null); @@ -49,14 +49,14 @@ public async Task Handle_AutoShowCompletionDisabled_NoCompletionItems() var uri = new Uri(documentPath); var documentContext = CreateDocumentContext(uri, codeDocument); var optionsMonitor = GetOptionsMonitor(autoShowCompletion: false); - var completionEndpoint = new RazorCompletionEndpoint(completionListProvider: null, telemetryReporter: null, optionsMonitor, LoggerFactory); + var completionEndpoint = new RazorCompletionEndpoint(completionListProvider: null, telemetryReporter: null, optionsMonitor); var request = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = uri }, - Position = new Position(0, 1), + Position = VsLspFactory.CreatePosition(0, 1), Context = new VSInternalCompletionContext() { InvokeKind = VSInternalCompletionInvokeKind.Typing }, }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs index befa32e49dc..174c2a11c51 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Completion/TagHelperCompletionProviderTest.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.Editor.Razor; using Xunit; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs index 0fa3ca8d176..bfae068bda8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorBreakpointSpanEndpointTest.cs @@ -39,7 +39,7 @@ public async Task Handle_UnsupportedDocument_ReturnsNull() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; codeDocument.SetUnsupported(); var requestContext = CreateRazorRequestContext(documentContext); @@ -64,9 +64,9 @@ public async Task Handle_StartsInHtml_BreakpointMoved() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; - var expectedRange = new Range { Start = new Position(1, 5), End = new Position(1, 19) }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 5, length: 14); var requestContext = CreateRazorRequestContext(documentContext); // Act @@ -89,9 +89,9 @@ public async Task Handle_ImplicitExpression_StartsInHtml_BreakpointMoved() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; - var expectedRange = new Range { Start = new Position(1, 4), End = new Position(1, 16) }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 4, length: 12); var requestContext = CreateRazorRequestContext(documentContext); // Act @@ -114,9 +114,9 @@ public async Task Handle_StartsInHtml_BreakpointMoved_Razor() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; - var expectedRange = new Range { Start = new Position(1, 5), End = new Position(1, 19) }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 5, length: 14); var requestContext = CreateRazorRequestContext(documentContext); // Act @@ -139,9 +139,9 @@ public async Task Handle_ImplicitExpression_StartsInHtml_BreakpointMoved_Razor() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; - var expectedRange = new Range { Start = new Position(1, 4), End = new Position(1, 16) }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 4, length: 12); var requestContext = CreateRazorRequestContext(documentContext); // Act @@ -165,7 +165,7 @@ public async Task Handle_StartsInHtml_InvalidBreakpointSpan_ReturnsNull() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -189,7 +189,7 @@ public async Task Handle_StartInHtml_NoCSharpOnLine_ReturnsNull() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -216,7 +216,7 @@ public async Task Handle_StartInHtml_NoActualCSharp_ReturnsNull() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(1, 0) + Position = VsLspFactory.CreatePosition(1, 0) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -243,7 +243,7 @@ public async Task Handle_InvalidBreakpointSpan_ReturnsNull() var request = new RazorBreakpointSpanParams() { Uri = documentPath, - Position = new Position(2, 0) + Position = VsLspFactory.CreatePosition(2, 0) }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs index 2f73d956dd0..e8bfb086782 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/RazorProximityExpressionsEndpointTest.cs @@ -39,7 +39,7 @@ public async Task Handle_UnsupportedDocument_ReturnsNull() var request = new RazorProximityExpressionsParams() { Uri = documentPath, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), }; codeDocument.SetUnsupported(); var requestContext = CreateRazorRequestContext(documentContext); @@ -64,7 +64,7 @@ public async Task Handle_ReturnsValidExpressions() var request = new RazorProximityExpressionsParams() { Uri = documentPath, - Position = new Position(1, 8), + Position = VsLspFactory.CreatePosition(1, 8), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -89,7 +89,7 @@ public async Task Handle_StartsInHtml_ReturnsValidExpressions() var request = new RazorProximityExpressionsParams() { Uri = documentPath, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -114,7 +114,7 @@ public async Task Handle_StartInHtml_NoCSharpOnLine_ReturnsNull() var request = new RazorProximityExpressionsParams() { Uri = documentPath, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -141,7 +141,7 @@ public async Task Handle_InvalidLocation_ReturnsNull() var request = new RazorProximityExpressionsParams() { Uri = documentPath, - Position = new Position(0, 0), + Position = VsLspFactory.DefaultPosition, }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/ValidateBreakpointRangeEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/ValidateBreakpointRangeEndpointTest.cs index 1c60c66ddec..1bc93112012 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/ValidateBreakpointRangeEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Debugging/ValidateBreakpointRangeEndpointTest.cs @@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; @@ -15,6 +14,7 @@ using Moq; using Xunit; using Xunit.Abstractions; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Debugging; @@ -133,7 +133,7 @@ private async Task VerifyBreakpointRangeAsync(string input) Assert.True(spans.TryGetValue("expected", out var expectedSpans), "Expected at least one span named 'expected'."); Assert.True(expectedSpans.Length == 1, "Expected only one 'expected' span."); - var expectedRange = expectedSpans[0].ToRange(codeDocument.GetSourceText()); + var expectedRange = codeDocument.Source.Text.GetRange(expectedSpans[0]); Assert.Equal(expectedRange, result); } @@ -149,7 +149,7 @@ private async Task VerifyBreakpointRangeAsync(string input) { Uri = new Uri(razorFilePath) }, - Range = breakpointSpan.ToRange(codeDocument.GetSourceText()) + Range = codeDocument.Source.Text.GetRange(breakpointSpan) }; Assert.True(DocumentContextFactory.TryCreateForOpenDocument(request.TextDocument, out var documentContext)); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs index 550b7671f2d..7526d0b052b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointDelegationTest.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -197,7 +196,7 @@ @namespace BlazorApp1.Shared // We can still expect the character to be correct, even if the line won't match var surveyPromptSourceText = SourceText.From(surveyPrompt); - var range = expectedSpan.ToRange(surveyPromptSourceText); + var range = surveyPromptSourceText.GetRange(expectedSpan); Assert.Equal(range.Start.Character, location.Range.Start.Character); } @@ -218,7 +217,7 @@ private async Task VerifyCSharpGoToDefinitionAsync(string input, string? filePat var location = Assert.Single(locations); Assert.Equal(new Uri(razorFilePath), location.Uri); - var expectedRange = expectedSpan.ToRange(codeDocument.GetSourceText()); + var expectedRange = codeDocument.Source.Text.GetRange(expectedSpan); Assert.Equal(expectedRange, location.Range); } @@ -245,14 +244,13 @@ await projectManager.UpdateAsync(updater => var endpoint = new DefinitionEndpoint(searchEngine, DocumentMappingService, LanguageServerFeatureOptions, languageServer, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); var request = new TextDocumentPositionParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(razorFilePath) }, - Position = new Position(line, offset) + Position = codeDocument.Source.Text.GetPosition(cursorPosition) }; return await endpoint.HandleRequestAsync(request, requestContext, DisposalToken); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs index 400b8cc671c..ebfb6b65708 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Definition/DefinitionEndpointTest.cs @@ -10,9 +10,9 @@ using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; using Xunit.Abstractions; @@ -393,7 +393,7 @@ private async Task VerifyNavigatePositionAsync(string content, string propertyNa TestFileMarkupParser.GetSpan(content, out content, out var selection); SetupDocument(out var codeDocument, out _, content); - var expectedRange = selection.ToRange(codeDocument.GetSourceText()); + var expectedRange = codeDocument.Source.Text.GetRange(selection); var mappingService = new RazorDocumentMappingService(FilePathService, new TestDocumentContextFactory(), LoggerFactory); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/CSharpDiagnosticsEndToEndTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/CSharpDiagnosticsEndToEndTest.cs index 8abd78c7507..8122d21ac0e 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/CSharpDiagnosticsEndToEndTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/CSharpDiagnosticsEndToEndTest.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -57,7 +56,7 @@ private async Task ValidateDiagnosticsAsync(string input, string? filePath = nul TestFileMarkupParser.GetSpans(input, out input, out ImmutableDictionary> spans); var codeDocument = CreateCodeDocument(input, filePath: filePath); - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var razorFilePath = "file://C:/path/test.razor"; var uri = new Uri(razorFilePath); var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath); @@ -82,7 +81,7 @@ private async Task ValidateDiagnosticsAsync(string input, string? filePath = nul { // If any future test requires multiple diagnostics of the same type, please change this code :) var diagnostic = Assert.Single(actual, d => d.Code == code); - Assert.Equal(span.First(), diagnostic.Range.ToTextSpan(sourceText)); + Assert.Equal(span.First(), sourceText.GetTextSpan(diagnostic.Range)); } } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticConverterTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticConverterTest.cs index f04188f9445..4e670005541 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticConverterTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticConverterTest.cs @@ -6,7 +6,6 @@ using System.Globalization; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; @@ -65,17 +64,13 @@ public void ConvertSpanToRange_ReturnsConvertedRange() // Arrange var sourceSpan = new SourceSpan(3, 0, 3, 4); var sourceText = SourceText.From("Hello World"); - var expectedRange = new Range - { - Start = new Position(0, 3), - End = new Position(0, 7) - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 0, character: 3, length: 4); // Act var range = RazorDiagnosticConverter.ConvertSpanToRange(sourceSpan, sourceText); // Assert - Assert.Equal("lo W", sourceText.GetSubTextString(range.ToTextSpan(sourceText))); + Assert.Equal("lo W", sourceText.GetSubTextString(sourceText.GetTextSpan(range))); Assert.Equal(expectedRange, range); } @@ -85,17 +80,13 @@ public void ConvertSpanToRange_StartsOutsideOfDocument_EmptyDocument_NormalizesT // Arrange var sourceText = SourceText.From(string.Empty); var sourceSpan = new SourceSpan(5, 0, 5, 4); - var expectedRange = new Range - { - Start = new Position(0, 0), - End = new Position(0, 0) - }; + var expectedRange = VsLspFactory.DefaultRange; // Act var range = RazorDiagnosticConverter.ConvertSpanToRange(sourceSpan, sourceText); // Assert - Assert.Equal("", sourceText.GetSubTextString(range.ToTextSpan(sourceText))); + Assert.Equal("", sourceText.GetSubTextString(sourceText.GetTextSpan(range))); Assert.Equal(expectedRange, range); } @@ -105,17 +96,13 @@ public void ConvertSpanToRange_StartsOutsideOfDocument_NormalizesToEnd() // Arrange var sourceText = SourceText.From("Hello World"); var sourceSpan = new SourceSpan(sourceText.Length + 5, 0, sourceText.Length + 5, 4); - var expectedRange = new Range - { - Start = new Position(0, 11), - End = new Position(0, 11) - }; + var expectedRange = VsLspFactory.CreateZeroWidthRange(0, 11); // Act var range = RazorDiagnosticConverter.ConvertSpanToRange(sourceSpan, sourceText); // Assert - Assert.Equal("", sourceText.GetSubTextString(range.ToTextSpan(sourceText))); + Assert.Equal("", sourceText.GetSubTextString(sourceText.GetTextSpan(range))); Assert.Equal(expectedRange, range); } @@ -125,17 +112,13 @@ public void ConvertSpanToRange_EndsOutsideOfDocument_NormalizesToEnd() // Arrange var sourceText = SourceText.From("Hello World"); var sourceSpan = new SourceSpan(6, 0, 6, 15); - var expectedRange = new Range - { - Start = new Position(0, 6), - End = new Position(0, 11) - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 0, character: 6, length: 5); // Act var range = RazorDiagnosticConverter.ConvertSpanToRange(sourceSpan, sourceText); // Assert - Assert.Equal("World", sourceText.GetSubTextString(range.ToTextSpan(sourceText))); + Assert.Equal("World", sourceText.GetSubTextString(sourceText.GetTextSpan(range))); Assert.Equal(expectedRange, range); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs index 598fa173d4d..e5910df49ec 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Diagnostics/RazorDiagnosticsPublisherTest.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -43,11 +42,7 @@ public class RazorDiagnosticsPublisherTest(ITestOutputHelper testOutput) : Langu Code = "TestCode", Severity = DiagnosticSeverity.Error, Message = "TestMessage", - Range = new Range() - { - Start = new Position(0,0), - End = new Position(0, 1) - } + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 0, length: 1) } ]; @@ -160,11 +155,7 @@ public async Task PublishDiagnosticsAsync_NewDocumentDiagnosticsGetPublished(boo Code = "TestCode", Severity = DiagnosticSeverity.Error, Message = "TestMessage", - Range = new Range() - { - Start = new Position(0,0), - End = new Position(0, 1) - } + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 0, length: 1) } }; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs index d8293a47274..59b5b074499 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentHighlighting/DocumentHighlightEndpointTest.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.AspNetCore.Razor.Test.Common.Mef; @@ -125,14 +126,13 @@ private async Task VerifyHighlightingRangesAsync(string input) var endpoint = new DocumentHighlightEndpoint( languageServerFeatureOptions, documentMappingService, languageServer, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); var request = new DocumentHighlightParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(razorFilePath) }, - Position = new Position(line, offset) + Position = codeDocument.Source.Text.GetPosition(cursorPosition) }; var documentContext = CreateDocumentContext(request.TextDocument.Uri, codeDocument); @@ -142,9 +142,9 @@ private async Task VerifyHighlightingRangesAsync(string input) var result = await endpoint.HandleRequestAsync(request, requestContext, DisposalToken); // Assert - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var expected = spans - .Select(s => s.ToRange(sourceText)) + .Select(sourceText.GetRange) .OrderBy(s => s.Start.Line) .ThenBy(s => s.Start.Character) .ToArray(); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs index 675a94387ee..f5af246e6e4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentTextPresentationEndpointTests.cs @@ -51,11 +51,7 @@ public async Task Handle_Html_MakesRequest() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Text = "Hi there" }; var requestContext = CreateRazorRequestContext(documentContext); @@ -94,11 +90,7 @@ public async Task Handle_CSharp_DoesNotMakeRequest() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Text = "Hi there" }; var requestContext = CreateRazorRequestContext(documentContext); @@ -139,11 +131,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Text = "Hi there" }; var requestContext = CreateRazorRequestContext(documentContext); @@ -185,11 +173,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Text = "Hi there" }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs index 1d3f98c8c9a..3e0c2fecef4 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentPresentation/TextDocumentUriPresentationEndpointTests.cs @@ -69,11 +69,7 @@ public async Task Handle_SimpleComponent_ReturnsResult() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [droppedUri] }; var requestContext = CreateRazorRequestContext(documentContext); @@ -83,7 +79,7 @@ public async Task Handle_SimpleComponent_ReturnsResult() // Assert Assert.NotNull(result); - Assert.Equal("", result!.DocumentChanges!.Value.First[0].Edits[0].NewText); + Assert.Equal("", result.DocumentChanges!.Value.First[0].Edits[0].NewText); } [OSSkipConditionFact(["OSX", "Linux"])] @@ -131,11 +127,7 @@ public async Task Handle_SimpleComponentWithChildFile_ReturnsResult() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [ new Uri("file:///c:/path/MyTagHelper.razor.cs"), @@ -204,11 +196,7 @@ public async Task Handle_ComponentWithRequiredAttribute_ReturnsResult() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [droppedUri] }; var requestContext = CreateRazorRequestContext(documentContext); @@ -218,7 +206,7 @@ public async Task Handle_ComponentWithRequiredAttribute_ReturnsResult() // Assert Assert.NotNull(result); - Assert.Equal("", result!.DocumentChanges!.Value.First[0].Edits[0].NewText); + Assert.Equal("", result.DocumentChanges!.Value.First[0].Edits[0].NewText); } [Fact] @@ -260,11 +248,7 @@ public async Task Handle_NoTypeNameIdentifier_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [droppedUri] }; var requestContext = CreateRazorRequestContext(documentContext); @@ -310,11 +294,7 @@ public async Task Handle_MultipleUris_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [ new Uri("file:///c:/path/SomeOtherFile.cs"), @@ -366,11 +346,7 @@ public async Task Handle_NotComponent_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [droppedUri] }; var requestContext = CreateRazorRequestContext(documentContext); @@ -428,11 +404,7 @@ public async Task Handle_ComponentWithNestedFiles_ReturnsResult() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1), Uris = [droppedUri1, droppedUri2] }; var requestContext = CreateRazorRequestContext(documentContext); @@ -481,11 +453,7 @@ public async Task Handle_CSharp_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - } + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -529,11 +497,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - } + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -578,11 +542,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - } + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -626,11 +586,7 @@ public async Task Handle_NoUris_ReturnsNull() { Uri = uri }, - Range = new Range - { - Start = new Position(0, 1), - End = new Position(0, 2) - } + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 1) }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSymbols/DocumentSymbolEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSymbols/DocumentSymbolEndpointTest.cs index 6ca34c78270..f8cbf5683e3 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSymbols/DocumentSymbolEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/DocumentSymbols/DocumentSymbolEndpointTest.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.LanguageServer.DocumentSymbols; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -143,8 +142,7 @@ private async Task VerifyDocumentSymbolsAsync(string input, bool hierarchical = foreach (var symbolInformation in symbolsInformations) { Assert.True(spansDict.TryGetValue(symbolInformation.Name, out var spans), $"Expected {symbolInformation.Name} to be in test provided markers"); - Assert.Single(spans); - var expectedRange = spans.Single().ToRange(sourceText); + var expectedRange = sourceText.GetRange(Assert.Single(spans)); Assert.Equal(expectedRange, symbolInformation.Location.Range); } } @@ -156,8 +154,7 @@ private static void VerifyDocumentSymbols(ImmutableDictionary FormatAsync(DocumentOnTypeFormatti { var generatedHtml = GetGeneratedHtml(@params.TextDocument.Uri); var generatedHtmlSource = SourceText.From(generatedHtml, Encoding.UTF8); - var absoluteIndex = @params.Position.GetRequiredAbsoluteIndex(generatedHtmlSource, logger: null); + var absoluteIndex = generatedHtmlSource.GetRequiredAbsoluteIndex(@params.Position); var request = $$""" { @@ -129,18 +128,8 @@ private async Task CallWebToolsApplyFormattedEd foreach (var textChange in response.TextChanges) { - var startLinePosition = sourceText.Lines.GetLinePosition(textChange.Position); - var endLinePosition = sourceText.Lines.GetLinePosition(textChange.Position + textChange.Length); - - var edit = new TextEdit() - { - Range = new() - { - Start = new(startLinePosition.Line, startLinePosition.Character), - End = new(endLinePosition.Line, endLinePosition.Character) - }, - NewText = textChange.NewText - }; + var span = new TextSpan(textChange.Position, textChange.Length); + var edit = VsLspFactory.CreateTextEdit(sourceText.GetRange(span), textChange.NewText); edits.Add(edit); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingLanguageServerTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingLanguageServerTestBase.cs index 725bbbe308b..25a4ba44e63 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingLanguageServerTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingLanguageServerTestBase.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit.Abstractions; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer.Formatting; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs index e35afe67684..9ec26d51add 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/FormattingTestBase.cs @@ -20,7 +20,6 @@ using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -66,7 +65,7 @@ private async Task RunFormattingTestAsync(string input, string expected, int tab var source = SourceText.From(input); var range = spans.IsEmpty ? null - : spans.Single().ToRange(source); + : source.GetRange(spans.Single()); var path = "file:///path/to/Document." + fileKind; var uri = new Uri(path); @@ -209,19 +208,11 @@ protected async Task RunCodeActionFormattingTestAsync( } protected static TextEdit Edit(int startLine, int startChar, int endLine, int endChar, string newText) - => new() - { - Range = new Range - { - Start = new Position(startLine, startChar), - End = new Position(endLine, endChar), - }, - NewText = newText, - }; + => VsLspFactory.CreateTextEdit(startLine, startChar, endLine, endChar, newText); private static SourceText ApplyEdits(SourceText source, TextEdit[] edits) { - var changes = edits.Select(e => e.ToTextChange(source)); + var changes = edits.Select(source.GetTextChange); return source.WithChanges(changes); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/RazorFormattingServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/RazorFormattingServiceTest.cs index e0c2db414ff..889ecd2cfaa 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/RazorFormattingServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Formatting_NetFx/RazorFormattingServiceTest.cs @@ -5,7 +5,6 @@ using System.Linq; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; @@ -27,24 +26,16 @@ public class Foo{} var sourceText = SourceText.From(source); var edits = new[] { - new TextEdit() - { - NewText = "Bar", - Range = new Range{ Start = new Position(2, 13), End = new Position(2, 16) } - }, - new TextEdit() - { - NewText = " ", - Range = new Range{Start = new Position(2, 0),End = new Position(2, 0)} - }, + VsLspFactory.CreateTextEdit(VsLspFactory.CreateSingleLineRange(line: 2, character: 13, length: 3), "Bar"), + VsLspFactory.CreateTextEdit(2, 0, " ") }; // Act var collapsedEdit = RazorFormattingService.MergeEdits(edits, sourceText); // Assert - var multiEditChange = sourceText.WithChanges(edits.Select(e => e.ToTextChange(sourceText))); - var singleEditChange = sourceText.WithChanges(collapsedEdit.ToTextChange(sourceText)); + var multiEditChange = sourceText.WithChanges(edits.Select(sourceText.GetTextChange)); + var singleEditChange = sourceText.WithChanges(sourceText.GetTextChange(collapsedEdit)); Assert.Equal(multiEditChange.ToString(), singleEditChange.ToString()); } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs index 89da1223b80..e2fa1ae18e1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/GeneratedDocumentPublisherTest.cs @@ -8,8 +8,8 @@ using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs index 489f6595489..335945678d6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Hover/HoverServiceTest.cs @@ -28,7 +28,6 @@ using Xunit; using Xunit.Abstractions; using static Microsoft.AspNetCore.Razor.LanguageServer.Tooltip.DefaultVSLSPTagHelperTooltipFactory; -using static Microsoft.CodeAnalysis.Razor.Workspaces.SourceTextExtensions; namespace Microsoft.AspNetCore.Razor.LanguageServer.Test.Hover; @@ -73,11 +72,7 @@ public async Task GetHoverInfo_TagHelper_Element() // Assert Assert.Contains("**Test1TagHelper**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 1), - End = new Position(1, 6), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5); Assert.Equal(expectedRange, hover.Range); } @@ -103,11 +98,7 @@ public async Task GetHoverInfo_TagHelper_Element_WithParent() // Assert Assert.Contains("**SomeChild**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(2, 5), - End = new Position(2, 14), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 2, character: 5, length: 9); Assert.Equal(expectedRange, hover.Range); } @@ -133,7 +124,7 @@ public async Task GetHoverInfo_TagHelper_Attribute_WithParent() // Assert Assert.Contains("**Attribute**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = span.ToRange(codeDocument.GetSourceText()); + var expectedRange = codeDocument.Source.Text.GetRange(span); Assert.Equal(expectedRange, hover.Range); } @@ -157,11 +148,7 @@ public async Task GetHoverInfo_TagHelper_Element_EndTag() // Assert Assert.Contains("**Test1TagHelper**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 9), - End = new Position(1, 14), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 9, length: 5); Assert.Equal(expectedRange, hover.Range); } @@ -186,11 +173,7 @@ public async Task GetHoverInfo_TagHelper_Attribute() // Assert Assert.Contains("**BoolVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.DoesNotContain("**IntVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 7), - End = new Position(1, 15), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 7, length: 8); Assert.Equal(expectedRange, hover.Range); } @@ -216,11 +199,7 @@ public async Task GetHoverInfo_TagHelper_AttributeTrailingEdge() // Assert Assert.Contains("**BoolVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.DoesNotContain("**IntVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 7), - End = new Position(1, 15), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 7, length: 8); Assert.Equal(expectedRange, hover.Range); } @@ -311,11 +290,7 @@ public async Task GetHoverInfo_TagHelper_MinimizedAttribute() // Assert Assert.Contains("**BoolVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.DoesNotContain("**IntVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 7), - End = new Position(1, 15), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 7, length: 8); Assert.Equal(expectedRange, hover.Range); } @@ -344,11 +319,7 @@ public void Increment(){ // Assert Assert.NotNull(hover); Assert.Contains("**Test**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 5), - End = new Position(1, 10), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 5, length: 5); Assert.Equal(expectedRange, hover.Range); } @@ -372,11 +343,7 @@ public async Task GetHoverInfo_TagHelper_MalformedElement() // Assert Assert.Contains("**Test1TagHelper**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 1), - End = new Position(1, 6), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5); Assert.Equal(expectedRange, hover.Range); } @@ -401,11 +368,7 @@ public async Task GetHoverInfo_TagHelper_MalformedAttribute() // Assert Assert.Contains("**BoolVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.DoesNotContain("**IntVal**", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); - var expectedRange = new Range - { - Start = new Position(1, 7), - End = new Position(1, 15), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 7, length: 8); Assert.Equal(expectedRange, hover.Range); } @@ -453,11 +416,7 @@ public async Task GetHoverInfo_TagHelper_PlainTextElement() // Assert Assert.Contains("Test1TagHelper", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.Equal(MarkupKind.PlainText, ((MarkupContent)hover.Contents).Kind); - var expectedRange = new Range - { - Start = new Position(1, 1), - End = new Position(1, 6), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5); Assert.Equal(expectedRange, hover.Range); } @@ -483,11 +442,7 @@ public async Task GetHoverInfo_TagHelper_PlainTextElement_EndTag() // Assert Assert.Contains("Test1TagHelper", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.Equal(MarkupKind.PlainText, ((MarkupContent)hover.Contents).Kind); - var expectedRange = new Range - { - Start = new Position(1, 9), - End = new Position(1, 14), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 9, length: 5); Assert.Equal(expectedRange, hover.Range); } @@ -512,11 +467,7 @@ public async Task GetHoverInfo_TagHelper_TextComponent() // Assert Assert.Contains("Text", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.Equal(MarkupKind.PlainText, ((MarkupContent)hover.Contents).Kind); - var expectedRange = new Range - { - Start = new Position(0, 1), - End = new Position(0, 5), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 0, character: 1, length: 4); Assert.Equal(expectedRange, hover.Range); } @@ -543,11 +494,7 @@ public async Task GetHoverInfo_TagHelper_TextComponent_NestedInHtml() // Assert Assert.Contains("Text", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.Equal(MarkupKind.PlainText, ((MarkupContent)hover.Contents).Kind); - var expectedRange = new Range - { - Start = new Position(1, 5), - End = new Position(1, 9), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 5, length: 4); Assert.Equal(expectedRange, hover.Range); } @@ -602,11 +549,7 @@ public async Task GetHoverInfo_TagHelper_TextComponent_NestedInCSharpAndText() // Assert Assert.Contains("Text", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.Equal(MarkupKind.PlainText, ((MarkupContent)hover.Contents).Kind); - var expectedRange = new Range - { - Start = new Position(3, 9), - End = new Position(3, 13), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 3, character: 9, length: 4); Assert.Equal(expectedRange, hover.Range); } @@ -633,11 +576,7 @@ public async Task GetHoverInfo_TagHelper_PlainTextAttribute() Assert.Contains("BoolVal", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.DoesNotContain("IntVal", ((MarkupContent)hover.Contents).Value, StringComparison.Ordinal); Assert.Equal(MarkupKind.PlainText, ((MarkupContent)hover.Contents).Kind); - var expectedRange = new Range - { - Start = new Position(1, 7), - End = new Position(1, 15), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 7, length: 8); Assert.Equal(expectedRange, hover.Range); } @@ -711,11 +650,7 @@ public async Task GetHoverInfo_TagHelper_Element_VSClient_ReturnVSHover() // Assert Assert.False(vsHover.Contents.Value.TryGetFourth(out var _)); Assert.True(vsHover.Contents.Value.TryGetThird(out var _) && !vsHover.Contents.Value.Third.Any()); - var expectedRange = new Range - { - Start = new Position(1, 1), - End = new Position(1, 6), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5); Assert.Equal(expectedRange, vsHover.Range); var container = (ContainerElement)vsHover.RawContent; @@ -756,11 +691,7 @@ public async Task GetHoverInfo_TagHelper_Attribute_VSClient_ReturnVSHover() // Assert Assert.False(vsHover.Contents.Value.TryGetFourth(out var _)); Assert.True(vsHover.Contents.Value.TryGetThird(out var markedStrings) && !markedStrings.Any()); - var expectedRange = new Range - { - Start = new Position(1, 7), - End = new Position(1, 15), - }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 1, character: 7, length: 8); Assert.Equal(expectedRange, vsHover.Range); var container = (ContainerElement)vsHover.RawContent; @@ -818,7 +749,7 @@ public async Task Handle_Hover_SingleServer_CallsDelegatedLanguageServer() { Uri = new Uri("C:/text.razor") }, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), }; var documentContext = CreateDefaultDocumentContext(); var requestContext = CreateRazorRequestContext(documentContext: documentContext); @@ -849,11 +780,7 @@ public async Task Handle_Hover_SingleServer_CSharpVariable() // Assert var range = result.Range; - var expected = new Range() - { - Start = new Position(line: 3, character: 8), - End = new Position(line: 3, character: 18) - }; + var expected = VsLspFactory.CreateSingleLineRange(line: 3, character: 8, length: 10); Assert.Equal(expected, range); @@ -883,11 +810,7 @@ public async Task Handle_Hover_SingleServer_Component() // Assert var range = result.Range; - var expected = new Range() - { - Start = new Position(line: 2, character: 1), - End = new Position(line: 2, character: 6) - }; + var expected = VsLspFactory.CreateSingleLineRange(line: 2, character: 1, length: 5); Assert.Equal(expected, range); @@ -968,7 +891,6 @@ private async Task GetResultFromSingleServerEndpointAsync(strin languageServer, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); var razorFileUri = new Uri(razorFilePath); var request = new TextDocumentPositionParams { @@ -976,7 +898,7 @@ private async Task GetResultFromSingleServerEndpointAsync(strin { Uri = razorFileUri, }, - Position = new Position(line, offset) + Position = codeDocument.Source.Text.GetPosition(cursorPosition) }; var documentContext = CreateDocumentContext(razorFileUri, codeDocument); var requestContext = CreateRazorRequestContext(documentContext: documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Implementation/ImplementationEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Implementation/ImplementationEndpointTest.cs index 556b54a9dbf..0dedf24fcda 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Implementation/ImplementationEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Implementation/ImplementationEndpointTest.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -98,14 +97,13 @@ private async Task VerifyCSharpGoToImplementationAsync(string input) var endpoint = new ImplementationEndpoint( LanguageServerFeatureOptions, DocumentMappingService, languageServer, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); var request = new TextDocumentPositionParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(razorFilePath) }, - Position = new Position(line, offset) + Position = codeDocument.Source.Text.GetPosition(cursorPosition) }; Assert.True(DocumentContextFactory.TryCreateForOpenDocument(request.TextDocument, out var documentContext)); var requestContext = CreateRazorRequestContext(documentContext); @@ -124,7 +122,7 @@ private async Task VerifyCSharpGoToImplementationAsync(string input) { Assert.Equal(new Uri(razorFilePath), location.Uri); - var expectedRange = expectedSpans[i].ToRange(codeDocument.GetSourceText()); + var expectedRange = codeDocument.Source.Text.GetRange(expectedSpans[i]); Assert.Equal(expectedRange, location.Range); i++; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs index 3dc9e041f34..82b4e407c2d 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/InlayHints/InlayHintEndpointTest.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -106,11 +105,7 @@ private async Task VerifyInlayHintsAsync(string input, Dictionary + Position = VsLspFactory.CreatePosition(1, 3) // }; var requestContext = CreateRazorRequestContext(documentContext: null); @@ -51,21 +51,13 @@ public async Task Handle_TagHelperStartTag_ReturnsCorrectRange() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 3 } // + Position = VsLspFactory.CreatePosition(1, 3) // }; - var expectedRanges = new Range[] + var expectedRanges = new[] { - new Range - { - Start = new Position { Line = 1, Character = 1 }, - End = new Position { Line = 1, Character = 6 } - }, - new Range - { - Start = new Position { Line = 1, Character = 9 }, - End = new Position { Line = 1, Character = 14 } - } + VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5), + VsLspFactory.CreateSingleLineRange(line: 1, character: 9, length: 5) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -92,21 +84,13 @@ public async Task Handle_TagHelperStartTag_ReturnsCorrectRange_EndSpan() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 6 } // + Position = VsLspFactory.CreatePosition(1, 6) // }; - var expectedRanges = new Range[] + var expectedRanges = new[] { - new Range - { - Start = new Position { Line = 1, Character = 1 }, - End = new Position { Line = 1, Character = 6 } - }, - new Range - { - Start = new Position { Line = 1, Character = 9 }, - End = new Position { Line = 1, Character = 14 } - } + VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5), + VsLspFactory.CreateSingleLineRange(line: 1, character: 9, length: 5) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -133,21 +117,13 @@ public async Task Handle_TagHelperEndTag_ReturnsCorrectRange() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 9 } // + Position = VsLspFactory.CreatePosition(1, 9) // }; - var expectedRanges = new Range[] + var expectedRanges = new[] { - new Range - { - Start = new Position { Line = 1, Character = 1 }, - End = new Position { Line = 1, Character = 6 } - }, - new Range - { - Start = new Position { Line = 1, Character = 9 }, - End = new Position { Line = 1, Character = 14 } - } + VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5), + VsLspFactory.CreateSingleLineRange(line: 1, character: 9, length: 5) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -174,7 +150,7 @@ public async Task Handle_NoTag_ReturnsNull() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 0, Character = 1 } // @[||]addTagHelper * + Position = VsLspFactory.CreatePosition(0, 1) // @[||]addTagHelper * }; var requestContext = CreateRazorRequestContext(documentContext); @@ -200,7 +176,7 @@ public async Task Handle_SelfClosingTagHelper_ReturnsNull() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 3 } // + Position = VsLspFactory.CreatePosition(1, 3) // }; var requestContext = CreateRazorRequestContext(documentContext); @@ -226,21 +202,13 @@ public async Task Handle_NestedTagHelperStartTags_ReturnsCorrectRange() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 1 } // <[||]test1> + Position = VsLspFactory.CreatePosition(1, 1) // <[||]test1> }; - var expectedRanges = new Range[] + var expectedRanges = new[] { - new Range - { - Start = new Position { Line = 1, Character = 1 }, - End = new Position { Line = 1, Character = 6 } - }, - new Range - { - Start = new Position { Line = 1, Character = 24 }, - End = new Position { Line = 1, Character = 29 } - } + VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 5), + VsLspFactory.CreateSingleLineRange(line: 1, character: 24, length: 5) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -267,21 +235,13 @@ public async Task Handle_HTMLStartTag_ReturnsCorrectRange() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 3 } // + Position = VsLspFactory.CreatePosition(1, 3) // }; - var expectedRanges = new Range[] + var expectedRanges = new[] { - new Range - { - Start = new Position { Line = 1, Character = 1 }, - End = new Position { Line = 1, Character = 5 } - }, - new Range - { - Start = new Position { Line = 1, Character = 8 }, - End = new Position { Line = 1, Character = 12 } - } + VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 4), + VsLspFactory.CreateSingleLineRange(line: 1, character: 8, length: 4) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -308,21 +268,13 @@ public async Task Handle_HTMLEndTag_ReturnsCorrectRange() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 8 } // + Position = VsLspFactory.CreatePosition(1, 8) // }; - var expectedRanges = new Range[] + var expectedRanges = new[] { - new Range - { - Start = new Position { Line = 1, Character = 1 }, - End = new Position { Line = 1, Character = 5 } - }, - new Range - { - Start = new Position { Line = 1, Character = 8 }, - End = new Position { Line = 1, Character = 12 } - } + VsLspFactory.CreateSingleLineRange(line: 1, character: 1, length: 4), + VsLspFactory.CreateSingleLineRange(line: 1, character: 8, length: 4) }; var requestContext = CreateRazorRequestContext(documentContext); @@ -349,7 +301,7 @@ public async Task Handle_SelfClosingHTMLTag_ReturnsNull() var request = new LinkedEditingRangeParams { TextDocument = new TextDocumentIdentifier { Uri = uri }, - Position = new Position { Line = 1, Character = 3 } // + Position = VsLspFactory.CreatePosition(1, 3) // }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs index 699575989dc..ba8a4a7fce8 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/MapCode/MapCodeTest.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.LanguageServer.Hosting; using Microsoft.AspNetCore.Razor.LanguageServer.MapCode; using Microsoft.AspNetCore.Razor.Telemetry; @@ -12,14 +13,12 @@ using Microsoft.AspNetCore.Razor.Test.Common.Mef; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; -using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Test.MapCode; @@ -278,7 +277,7 @@ private async Task VerifyCodeMappingAsync( string[] codeToMap, string expectedCode, string razorFilePath = RazorFilePath, - LSP.Location[][]? locations = null) + Location[][]? locations = null) { // Arrange TestFileMarkupParser.GetPositionAndSpans(originalCode, out var output, out int cursorPosition, out ImmutableArray spans); @@ -302,8 +301,7 @@ private async Task VerifyCodeMappingAsync( capabilitiesProvider.ApplyCapabilities(serverCapabilities, new()); Assert.True(serverCapabilities.MapCodeProvider); - var sourceText = codeDocument.GetSourceText(); - sourceText.GetLineAndOffset(cursorPosition, out var line, out var offset); + var sourceText = codeDocument.Source.Text; var mappings = new VSInternalMapCodeMapping[] { @@ -317,11 +315,7 @@ private async Task VerifyCodeMappingAsync( [ new Location { - Range = new Range - { - Start = new Position(line, offset), - End = new Position(line, offset) - }, + Range = sourceText.GetZeroWidthRange(cursorPosition), Uri = new Uri(razorFilePath) } ] @@ -402,7 +396,7 @@ private static SourceText ApplyWorkspaceEdit(WorkspaceEdit workspaceEdit, Uri do foreach (var currentEdit in edit.Edits) { - sourceText = sourceText.WithChanges(currentEdit.ToTextChange(sourceText)); + sourceText = sourceText.WithChanges(sourceText.GetTextChange(currentEdit)); } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs index e8a479682ed..7f056bbde56 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorLanguageQueryEndpointTest.cs @@ -41,7 +41,7 @@ public async Task Handle_ResolvesLanguageRequest_Razor() var request = new RazorLanguageQueryParams() { Uri = documentPath, - Position = new Position(0, 1), + Position = VsLspFactory.CreatePosition(0, 1), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -68,7 +68,7 @@ public async Task Handle_ResolvesLanguageRequest_Html() var request = new RazorLanguageQueryParams() { Uri = documentPath, - Position = new Position(0, 2), + Position = VsLspFactory.CreatePosition(0, 2), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -98,7 +98,7 @@ public async Task Handle_ResolvesLanguageRequest_CSharp() var request = new RazorLanguageQueryParams() { Uri = documentPath, - Position = new Position(0, 1), + Position = VsLspFactory.CreatePosition(0, 1), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -129,7 +129,7 @@ public async Task Handle_Unsupported_ResolvesLanguageRequest_Html() var request = new RazorLanguageQueryParams() { Uri = documentPath, - Position = new Position(0, 1), + Position = VsLspFactory.CreatePosition(0, 1), }; var requestContext = CreateRazorRequestContext(documentContext); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs index a5bb275644e..60cad5462b1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Mapping/RazorMapToDocumentRangesEndpointTest.cs @@ -4,15 +4,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Language; -using Microsoft.AspNetCore.Razor.Language.CodeGeneration; using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using Xunit.Abstractions; @@ -41,20 +38,20 @@ public async Task Handle_MapToDocumentRanges_CSharp() var codeDocument = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "var __o = DateTime.Now", - new[] { + [ new SourceMapping( new SourceSpan(4, 12), new SourceSpan(10, 12)) - }); + ]); var documentContext = CreateDocumentContext(documentPath, codeDocument); var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, - ProjectedRanges = new[] { new Range { Start = new Position(0, 10), End = new Position(0, 22) }, }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(line: 0, character: 10, length: 12)], RazorDocumentUri = documentPath, }; - var expectedRange = new Range { Start = new Position(0, 4), End = new Position(0, 16) }; + var expectedRange = VsLspFactory.CreateSingleLineRange(line: 0, character: 4, length: 12); var requestContext = CreateRazorRequestContext(documentContext); @@ -75,17 +72,17 @@ public async Task Handle_MapToDocumentRanges_CSharp_Unmapped() var codeDocument = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "var __o = DateTime.Now", - new[] { + [ new SourceMapping( new SourceSpan(4, 12), new SourceSpan(10, 12)) - }); + ]); var documentContext = CreateDocumentContext(documentPath, codeDocument); var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, - ProjectedRanges = new[] { new Range { Start = new Position(0, 0), End = new Position(0, 3) } }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 3)], RazorDocumentUri = documentPath, }; @@ -96,7 +93,7 @@ public async Task Handle_MapToDocumentRanges_CSharp_Unmapped() // Assert Assert.NotNull(response); - Assert.Equal(RangeExtensions.UndefinedRange, response!.Ranges[0]); + Assert.Equal(VsLspFactory.UndefinedRange, response!.Ranges[0]); Assert.Equal(1337, response.HostDocumentVersion); } @@ -108,17 +105,17 @@ public async Task Handle_MapToDocumentRanges_CSharp_LeadingOverlapsUnmapped() var codeDocument = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "var __o = DateTime.Now", - new[] { + [ new SourceMapping( new SourceSpan(4, 12), new SourceSpan(10, 12)) - }); + ]); var documentContext = CreateDocumentContext(documentPath, codeDocument); var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, - ProjectedRanges = new[] { new Range { Start = new Position(0, 0), End = new Position(0, 22) } }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 22)], RazorDocumentUri = documentPath, }; @@ -129,7 +126,7 @@ public async Task Handle_MapToDocumentRanges_CSharp_LeadingOverlapsUnmapped() // Assert Assert.NotNull(response); - Assert.Equal(RangeExtensions.UndefinedRange, response!.Ranges[0]); + Assert.Equal(VsLspFactory.UndefinedRange, response!.Ranges[0]); Assert.Equal(1337, response.HostDocumentVersion); } @@ -141,17 +138,17 @@ public async Task Handle_MapToDocumentRanges_CSharp_TrailingOverlapsUnmapped() var codeDocument = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "var __o = DateTime.Now", - new[] { + [ new SourceMapping( new SourceSpan(4, 12), new SourceSpan(10, 12)) - }); + ]); var documentContext = CreateDocumentContext(documentPath, codeDocument); var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, - ProjectedRanges = new[] { new Range { Start = new Position(0, 10), End = new Position(0, 23) } }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(line: 0, character : 10, length: 13)], RazorDocumentUri = documentPath, }; @@ -162,7 +159,7 @@ public async Task Handle_MapToDocumentRanges_CSharp_TrailingOverlapsUnmapped() // Assert Assert.NotNull(response); - Assert.Equal(RangeExtensions.UndefinedRange, response!.Ranges[0]); + Assert.Equal(VsLspFactory.UndefinedRange, response!.Ranges[0]); Assert.Equal(1337, response.HostDocumentVersion); } @@ -177,7 +174,7 @@ public async Task Handle_MapToDocumentRanges_Html() var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.Html, - ProjectedRanges = new[] { new Range { Start = new Position(0, 16), End = new Position(0, 20) } }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(line: 0, character: 16, length: 4)], RazorDocumentUri = documentPath, }; @@ -203,7 +200,7 @@ public async Task Handle_MapToDocumentRanges_Razor() var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.Razor, - ProjectedRanges = new[] { new Range { Start = new Position(0, 3), End = new Position(0, 4) } }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(line: 0, character: 4, length: 1)], RazorDocumentUri = documentPath, }; @@ -226,18 +223,18 @@ public async Task Handle_MapToDocumentRanges_Unsupported() var codeDocument = CreateCodeDocumentWithCSharpProjection( "

@DateTime.Now

", "var __o = DateTime.Now", - new[] { + [ new SourceMapping( new SourceSpan(4, 12), new SourceSpan(10, 12)) - }); + ]); codeDocument.SetUnsupported(); var documentContext = CreateDocumentContext(documentPath, codeDocument); var languageEndpoint = new RazorMapToDocumentRangesEndpoint(_mappingService); var request = new RazorMapToDocumentRangesParams() { Kind = RazorLanguageKind.CSharp, - ProjectedRanges = new[] { new Range { Start = new Position(0, 10), End = new Position(0, 22) } }, + ProjectedRanges = [VsLspFactory.CreateSingleLineRange(line: 0, character: 10, length: 12)], RazorDocumentUri = documentPath, }; @@ -248,20 +245,20 @@ public async Task Handle_MapToDocumentRanges_Unsupported() // Assert Assert.NotNull(response); - Assert.Equal(RangeExtensions.UndefinedRange, response!.Ranges[0]); + Assert.Equal(VsLspFactory.UndefinedRange, response!.Ranges[0]); Assert.Equal(1337, response.HostDocumentVersion); } private static RazorCodeDocument CreateCodeDocumentWithCSharpProjection(string razorSource, string projectedCSharpSource, IEnumerable sourceMappings) { - var codeDocument = CreateCodeDocument(razorSource, ImmutableArray.Empty); + var codeDocument = CreateCodeDocument(razorSource, tagHelpers: []); var csharpDocument = RazorCSharpDocument.Create( codeDocument, projectedCSharpSource, RazorCodeGenerationOptions.CreateDefault(), - Enumerable.Empty(), + diagnostics: [], sourceMappings.ToImmutableArray(), - Enumerable.Empty()); + linePragmas: []); codeDocument.SetCSharpDocument(csharpDocument); return codeDocument; } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Microsoft.AspNetCore.Razor.LanguageServer.Test.csproj b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Microsoft.AspNetCore.Razor.LanguageServer.Test.csproj index 4eff1502514..ab200262e88 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Microsoft.AspNetCore.Razor.LanguageServer.Test.csproj +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Microsoft.AspNetCore.Razor.LanguageServer.Test.csproj @@ -20,10 +20,6 @@ 4.7.0-1.23178.15 - - - - diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RangeExtensionsTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RangeExtensionsTests.cs index 69cae01475d..98e5dc223d1 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RangeExtensionsTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/RangeExtensionsTests.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; @@ -14,8 +13,8 @@ public class RangeExtensionsTests public void CompareTo_StartAndEndAreSame_ReturnsZero() { // Arrange - var range1 = new Range() { Start = new Position(1, 2), End = new Position(3, 4) }; - var range2 = new Range() { Start = new Position(1, 2), End = new Position(3, 4) }; + var range1 = VsLspFactory.CreateRange(1, 2, 3, 4); + var range2 = VsLspFactory.CreateRange(1, 2, 3, 4); // Act var result = range1.CompareTo(range2); @@ -28,8 +27,8 @@ public void CompareTo_StartAndEndAreSame_ReturnsZero() public void CompareTo_StartOfThisRangeIsBeforeOther_ReturnsNegative() { // Arrange - var range1 = new Range() { Start = new Position(1, 2), End = new Position(3, 4) }; - var range2 = new Range() { Start = new Position(2, 2), End = new Position(3, 4) }; + var range1 = VsLspFactory.CreateRange(1, 2, 3, 4); + var range2 = VsLspFactory.CreateRange(2, 2, 3, 4); // Act var result = range1.CompareTo(range2); @@ -42,8 +41,8 @@ public void CompareTo_StartOfThisRangeIsBeforeOther_ReturnsNegative() public void CompareTo_EndOfThisRangeIsBeforeOther_ReturnsNegative() { // Arrange - var range1 = new Range() { Start = new Position(1, 2), End = new Position(3, 4) }; - var range2 = new Range() { Start = new Position(1, 2), End = new Position(4, 4) }; + var range1 = VsLspFactory.CreateRange(1, 2, 3, 4); + var range2 = VsLspFactory.CreateRange(1, 2, 4, 4); // Act var result = range1.CompareTo(range2); @@ -56,8 +55,8 @@ public void CompareTo_EndOfThisRangeIsBeforeOther_ReturnsNegative() public void CompareTo_StartOfThisRangeIsAfterOther_ReturnsPositive() { // Arrange - var range1 = new Range() { Start = new Position(2, 2), End = new Position(3, 4) }; - var range2 = new Range() { Start = new Position(1, 2), End = new Position(3, 4) }; + var range1 = VsLspFactory.CreateRange(2, 2, 3, 4); + var range2 = VsLspFactory.CreateRange(1, 2, 3, 4); // Act var result = range1.CompareTo(range2); @@ -70,8 +69,8 @@ public void CompareTo_StartOfThisRangeIsAfterOther_ReturnsPositive() public void CompareTo_EndOfThisRangeIsAfterOther_ReturnsPositive() { // Arrange - var range1 = new Range() { Start = new Position(1, 2), End = new Position(4, 4) }; - var range2 = new Range() { Start = new Position(1, 2), End = new Position(3, 4) }; + var range1 = VsLspFactory.CreateRange(1, 2, 4, 4); + var range2 = VsLspFactory.CreateRange(1, 2, 3, 4); // Act var result = range1.CompareTo(range2); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs index 0a5230fc06e..f11cb0b851f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointDelegationTest.cs @@ -9,8 +9,8 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Test.Common.Mef; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using Xunit.Abstractions; @@ -73,14 +73,13 @@ await projectManager.UpdateAsync(updater => languageServer, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); var request = new RenameParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(razorFilePath) }, - Position = new Position(line, offset), + Position = codeDocument.Source.Text.GetPosition(cursorPosition), NewName = newName }; Assert.True(DocumentContextFactory.TryCreateForOpenDocument(request.TextDocument, out var documentContext)); @@ -90,8 +89,8 @@ await projectManager.UpdateAsync(updater => var result = await endpoint.HandleRequestAsync(request, requestContext, DisposalToken); // Assert - var edits = result.DocumentChanges.Value.First.FirstOrDefault().Edits.Select(e => e.ToTextChange(codeDocument.GetSourceText())); - var newText = codeDocument.GetSourceText().WithChanges(edits).ToString(); + var edits = result.DocumentChanges.Value.First.FirstOrDefault().Edits.Select(codeDocument.Source.Text.GetTextChange); + var newText = codeDocument.Source.Text.WithChanges(edits).ToString(); Assert.Equal(expected, newText); } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs index ad0b9fa8186..879c0bf5fbe 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Refactoring/RenameEndpointTest.cs @@ -117,7 +117,7 @@ public async Task Handle_Rename_FileManipulationNotSupported_ReturnsNull() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(2, 1), + Position = VsLspFactory.CreatePosition(2, 1), NewName = "Component5" }; @@ -140,7 +140,7 @@ public async Task Handle_Rename_WithNamespaceDirective() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(2, 1), + Position = VsLspFactory.CreatePosition(2, 1), NewName = "Component5" }; @@ -181,7 +181,7 @@ public async Task Handle_Rename_OnComponentParameter_ReturnsNull() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 14), + Position = VsLspFactory.CreatePosition(1, 14), NewName = "Test2" }; @@ -204,7 +204,7 @@ public async Task Handle_Rename_OnOpeningBrace_ReturnsNull() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), NewName = "Test2" }; @@ -227,7 +227,7 @@ public async Task Handle_Rename_OnComponentNameLeadingEdge_ReturnsResult() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 1), + Position = VsLspFactory.CreatePosition(1, 1), NewName = "Test2" }; @@ -250,7 +250,7 @@ public async Task Handle_Rename_OnComponentName_ReturnsResult() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 3), + Position = VsLspFactory.CreatePosition(1, 3), NewName = "Test2" }; @@ -273,7 +273,7 @@ public async Task Handle_Rename_OnComponentNameTrailingEdge_ReturnsResult() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 10), + Position = VsLspFactory.CreatePosition(1, 10), NewName = "Test2" }; @@ -296,7 +296,7 @@ public async Task Handle_Rename_ComponentInSameFile() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 1), + Position = VsLspFactory.CreatePosition(1, 1), NewName = "Component5" }; @@ -382,7 +382,7 @@ public async Task Handle_Rename_FullyQualifiedAndNot() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(2, 1), + Position = VsLspFactory.CreatePosition(2, 1), NewName = "Component5" }; @@ -428,7 +428,7 @@ public async Task Handle_Rename_MultipleFileUsages() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 1), + Position = VsLspFactory.CreatePosition(1, 1), NewName = "Component5" }; @@ -481,7 +481,7 @@ public async Task Handle_Rename_DifferentDirectories() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 1), + Position = VsLspFactory.CreatePosition(1, 1), NewName = "TestComponent" }; @@ -546,7 +546,7 @@ public async Task Handle_Rename_SingleServer_CallsDelegatedLanguageServer() var request = new RenameParams { TextDocument = new() { Uri = uri }, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), NewName = "Test2" }; @@ -580,7 +580,7 @@ public async Task Handle_Rename_SingleServer_DoesNotDelegateForRazor() var request = new RenameParams { TextDocument = new() { Uri = PathUtilities.GetUri(s_componentWithParamFilePath) }, - Position = new Position(1, 0), + Position = VsLspFactory.CreatePosition(1, 0), NewName = "Test2" }; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs index 836256d0edb..4c460d0cffd 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/SemanticTokensTest.cs @@ -878,7 +878,7 @@ public void GetMappedCSharpRanges_MinimalRangeVsSmallDisjointRanges_DisjointRang for (var i = 0; i < csharpRanges.Length; i++) { var csharpRange = csharpRanges[i]; - var textSpan = csharpRange.ToTextSpan(csharpSourceText); + var textSpan = csharpSourceText.GetTextSpan(csharpRange); Assert.Equal(spans[i].Length, textSpan.Length); } } @@ -887,7 +887,7 @@ public void GetMappedCSharpRanges_MinimalRangeVsSmallDisjointRanges_DisjointRang // Note that the expected lengths are different on Windows vs. Unix. var expectedCsharpRangeLength = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 945 : 911; Assert.True(codeDocument.TryGetMinimalCSharpRange(razorRange, out var csharpRange)); - var textSpan = csharpRange.ToTextSpan(csharpSourceText); + var textSpan = csharpSourceText.GetTextSpan(csharpRange); Assert.Equal(expectedCsharpRangeLength, textSpan.Length); } } @@ -945,7 +945,7 @@ private static VersionedDocumentContext CreateDocumentContext( .Returns(projectSnapshot.Object); documentContext.Setup(d => d.GetSourceTextAsync(It.IsAny())) - .Returns(Task.FromResult(document.GetSourceText())); + .Returns(Task.FromResult(document.Source.Text)); documentContext.Setup(d => d.Uri) .Returns(new Uri($"c:\\${(isRazorFile ? RazorFile : CSHtmlFile)}")); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SignatureHelp/SignatureHelpEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SignatureHelp/SignatureHelpEndpointTest.cs index e1d816083a6..b794fc1ece3 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SignatureHelp/SignatureHelpEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SignatureHelp/SignatureHelpEndpointTest.cs @@ -7,7 +7,6 @@ using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -104,14 +103,13 @@ private async Task VerifySignatureHelpWithContextAndOptionsAsync(string input, R var endpoint = new SignatureHelpEndpoint( LanguageServerFeatureOptions, DocumentMappingService, languageServer, optionsMonitor, LoggerFactory); - codeDocument.GetSourceText().GetLineAndOffset(cursorPosition, out var line, out var offset); var request = new SignatureHelpParams { TextDocument = new TextDocumentIdentifier { Uri = new Uri(razorFilePath) }, - Position = new Position(line, offset), + Position = codeDocument.Source.Text.GetPosition(cursorPosition), Context = signatureHelpContext }; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs index edd88582b8c..f8d2fdd96b6 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SingleServerDelegatingEndpointTestBase.TestLanguageServer.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Protocol.Diagnostics; using Microsoft.CodeAnalysis.Razor.Protocol.Folding; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; using DefinitionResult = Microsoft.VisualStudio.LanguageServer.Protocol.SumType< @@ -23,6 +22,7 @@ using ImplementationResult = Microsoft.VisualStudio.LanguageServer.Protocol.SumType< Microsoft.VisualStudio.LanguageServer.Protocol.Location[], Microsoft.VisualStudio.LanguageServer.Protocol.VSInternalReferenceItem[]>; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.AspNetCore.Razor.LanguageServer; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SpellCheck/DocumentSpellCheckEndpointTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SpellCheck/DocumentSpellCheckEndpointTest.cs index 4a374d5e84f..72f9c894e4f 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SpellCheck/DocumentSpellCheckEndpointTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/SpellCheck/DocumentSpellCheckEndpointTest.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -168,7 +167,7 @@ private async Task ValidateSpellCheckRangesAsync(string originalInput, string? f TestFileMarkupParser.GetSpans(originalInput, out var testInput, out ImmutableArray spans); var codeDocument = CreateCodeDocument(testInput, filePath: filePath); - var sourceText = codeDocument.GetSourceText(); + var sourceText = codeDocument.Source.Text; var razorFilePath = "file://C:/path/test.razor"; var uri = new Uri(razorFilePath); var languageServer = await CreateLanguageServerAsync(codeDocument, razorFilePath, additionalRazorDocuments); diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs index 1563ace5179..4e4bba21832 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/TagHelperFactsServiceTest.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.LanguageServer.Completion; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.Editor.Razor; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs index d7b3adbaac6..fc85888a50b 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/WrapWithTag/WrapWithTagEndpointTests.cs @@ -12,7 +12,6 @@ using Microsoft.CodeAnalysis.Razor.DocumentMapping; using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.VisualStudio.LanguageServer.Protocol; using Moq; using Xunit; @@ -45,7 +44,7 @@ public async Task Handle_Html_ReturnsResult() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = uri }) { - Range = new Range { Start = new Position(0, 0), End = new Position(0, 2) }, + Range = VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 2), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -80,7 +79,7 @@ public async Task Handle_CSharp_ReturnsNull() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = uri }) { - Range = new Range { Start = new Position(0, 0), End = new Position(0, 2) }, + Range = VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 2), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -115,7 +114,7 @@ public async Task Handle_CSharp_WholeImplicitStatement_ReturnsResult() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = uri }) { - Range = new Range { Start = new Position(0, 0), End = new Position(0, 8) }, + Range = VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 8), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -150,7 +149,7 @@ public async Task Handle_CSharp_PartOfImplicitStatement_ReturnsNull() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = uri }) { - Range = new Range { Start = new Position(0, 2), End = new Position(0, 4) }, + Range = VsLspFactory.CreateSingleLineRange(line: 0, character: 2, length: 2), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -185,7 +184,7 @@ public async Task Handle_CSharp_InImplicitStatement_ReturnsResult() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = uri }) { - Range = new Range { Start = new Position(0, 4), End = new Position(0, 4) }, + Range = VsLspFactory.CreateZeroWidthRange(0, 4), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -213,7 +212,7 @@ public async Task Handle_DocumentNotFound_ReturnsNull() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = missingUri }) { - Range = new Range { Start = new Position(0, 0), End = new Position(0, 2) }, + Range = VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 2), }; var requestContext = CreateRazorRequestContext(documentContext: null); @@ -241,7 +240,7 @@ public async Task Handle_UnsupportedCodeDocument_ReturnsNull() var wrapWithDivParams = new WrapWithTagParams(new TextDocumentIdentifier { Uri = uri }) { - Range = new Range { Start = new Position(0, 0), End = new Position(0, 2) }, + Range = VsLspFactory.CreateSingleLineRange(start: (0, 0), length: 2), }; var requestContext = CreateRazorRequestContext(documentContext); @@ -275,28 +274,18 @@ public async Task CleanUpTextEdits_NoTilde() var computedEdits = new TextEdit[] { - new() - { - NewText="
" + Environment.NewLine + " ", - Range = new Range { Start= new Position(0, 0), End = new Position(0, 0) } - }, - new() - { - NewText=" ", - Range = new Range { Start= new Position(1, 0), End = new Position(1, 0) } - }, - new() - { - NewText=" }" + Environment.NewLine + "
", - Range = new Range { Start= new Position(2, 0), End = new Position(2, 1) } - } + VsLspFactory.CreateTextEdit(position: (0, 0), "
" + Environment.NewLine + " "), + VsLspFactory.CreateTextEdit(line: 1, character: 0, " "), + VsLspFactory.CreateTextEdit( + range: VsLspFactory.CreateSingleLineRange(line: 2, character: 0, length: 1), + newText: " }" + Environment.NewLine + "
"), }; var htmlSourceText = await context!.GetHtmlSourceTextAsync(DisposalToken); var edits = HtmlFormatter.FixHtmlTestEdits(htmlSourceText, computedEdits); Assert.Same(computedEdits, edits); - var finalText = inputSourceText.WithChanges(edits.Select(e => e.ToTextChange(inputSourceText))); + var finalText = inputSourceText.WithChanges(edits.Select(inputSourceText.GetTextChange)); Assert.Equal(expected, finalText.ToString()); } @@ -324,29 +313,19 @@ public async Task CleanUpTextEdits_BadEditWithTilde() var computedEdits = new TextEdit[] { - new() - { - NewText="
" + Environment.NewLine + " ", - Range = new Range { Start= new Position(0, 0), End = new Position(0, 0) } - }, - new() - { - NewText=" ", - Range = new Range { Start= new Position(1, 0), End = new Position(1, 0) } - }, - new() - { - // This is the problematic edit.. the close brace has been replaced with a tilde - NewText=" ~" + Environment.NewLine + "
", - Range = new Range { Start= new Position(2, 0), End = new Position(2, 1) } - } + VsLspFactory.CreateTextEdit(position: (0, 0), "
" + Environment.NewLine + " "), + VsLspFactory.CreateTextEdit(line: 1, character: 0, " "), + // This is the problematic edit.. the close brace has been replaced with a tilde + VsLspFactory.CreateTextEdit( + range: VsLspFactory.CreateSingleLineRange(line: 2, character: 0, length: 1), + newText: " ~" + Environment.NewLine + "
") }; var htmlSourceText = await context!.GetHtmlSourceTextAsync(DisposalToken); var edits = HtmlFormatter.FixHtmlTestEdits(htmlSourceText, computedEdits); Assert.NotSame(computedEdits, edits); - var finalText = inputSourceText.WithChanges(edits.Select(e => e.ToTextChange(inputSourceText))); + var finalText = inputSourceText.WithChanges(edits.Select(inputSourceText.GetTextChange)); Assert.Equal(expected, finalText.ToString()); } @@ -370,33 +349,23 @@ public async Task CleanUpTextEdits_GoodEditWithTilde() var uri = new Uri("file://path.razor"); var factory = CreateDocumentContextFactory(uri, input); Assert.True(factory.TryCreate(uri, out var context)); - var inputSourceText = await context!.GetSourceTextAsync(DisposalToken); + var inputSourceText = await context.GetSourceTextAsync(DisposalToken); - var computedEdits = new TextEdit[] + var computedEdits = new[] { - new() - { - NewText="
" + Environment.NewLine + " ", - Range = new Range { Start= new Position(0, 0), End = new Position(0, 0) } - }, - new() - { - NewText=" ", - Range = new Range { Start= new Position(1, 0), End = new Position(1, 0) } - }, - new() - { - // This looks like a bad edit, but the original source document had a tilde - NewText=" ~" + Environment.NewLine + "
", - Range = new Range { Start= new Position(2, 0), End = new Position(2, 1) } - } + VsLspFactory.CreateTextEdit(position: (0, 0), "
" + Environment.NewLine + " "), + VsLspFactory.CreateTextEdit(line: 1, character: 0, " "), + // This looks like a bad edit, but the original source document had a tilde + VsLspFactory.CreateTextEdit( + range: VsLspFactory.CreateSingleLineRange(line: 2, character: 0, length: 1), + newText: " ~" + Environment.NewLine + "
") }; - var htmlSourceText = await context!.GetHtmlSourceTextAsync(DisposalToken); + var htmlSourceText = await context.GetHtmlSourceTextAsync(DisposalToken); var edits = HtmlFormatter.FixHtmlTestEdits(htmlSourceText, computedEdits); Assert.NotSame(computedEdits, edits); - var finalText = inputSourceText.WithChanges(edits.Select(e => e.ToTextChange(inputSourceText))); + var finalText = inputSourceText.WithChanges(edits.Select(inputSourceText.GetTextChange)); Assert.Equal(expected, finalText.ToString()); } } diff --git a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs index 5678946116b..27d2273b814 100644 --- a/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs +++ b/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestDocumentContext.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; -using Microsoft.CodeAnalysis.Razor.Workspaces; namespace Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; @@ -22,7 +21,7 @@ public static DocumentContext Create(Uri uri, string text) public static VersionedDocumentContext From(string filePath, RazorCodeDocument codeDocument, int hostDocumentVersion) { - var content = codeDocument.GetSourceText().ToString(); + var content = codeDocument.Source.Text.ToString(); var documentSnapshot = TestDocumentSnapshot.Create(filePath, content); documentSnapshot.With(codeDocument); var uri = new Uri(filePath); @@ -31,7 +30,7 @@ public static VersionedDocumentContext From(string filePath, RazorCodeDocument c public static DocumentContext From(string filePath, RazorCodeDocument codeDocument) { - var content = codeDocument.GetSourceText().ToString(); + var content = codeDocument.Source.Text.ToString(); var documentSnapshot = TestDocumentSnapshot.Create(filePath, content); documentSnapshot.With(codeDocument); var uri = new Uri(filePath); diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderBaseTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderBaseTest.cs index 5494891c8c7..05bfe069bb0 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderBaseTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderBaseTest.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.IntegrationTests; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Text; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.cs index 78ba765c9c3..0611fa33c80 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeCompletionItemProviderTest.cs @@ -9,7 +9,7 @@ using System.Linq; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.IntegrationTests; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeParameterCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeParameterCompletionItemProviderTest.cs index 8c384bb6557..81f39a30d88 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeParameterCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveAttributeParameterCompletionItemProviderTest.cs @@ -7,7 +7,7 @@ using System.Collections.Immutable; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.IntegrationTests; -using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.AspNetCore.Razor.Language.Syntax; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs index 9d6fb4e4872..c918aa2339b 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/Completion/DirectiveCompletionItemProviderTest.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.AspNetCore.Razor.Test.Common; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs index f1438f53a19..44f5eef3136 100644 --- a/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs +++ b/src/Razor/test/Microsoft.CodeAnalysis.Razor.Workspaces.Test/ProjectSystem/DefaultDocumentSnapshotTest.cs @@ -3,10 +3,10 @@ using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Xunit; using Xunit.Abstractions; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentHighlightEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentHighlightEndpointTest.cs index ef1c4e4777c..ce044474c00 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentHighlightEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentHighlightEndpointTest.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -150,7 +149,7 @@ private async Task VerifyDocumentHighlightsAsync(string input, DocumentHighlight TestFileMarkupParser.GetPositionAndSpans(input, out var source, out int cursorPosition, out ImmutableArray spans); var document = CreateProjectAndRazorDocument(source); var inputText = await document.GetTextAsync(DisposalToken); - inputText.GetLineAndOffset(cursorPosition, out var lineIndex, out var characterIndex); + var position = inputText.GetPosition(cursorPosition); var requestInvoker = new TestLSPRequestInvoker([(Methods.TextDocumentDocumentHighlightName, htmlResponse)]); @@ -159,7 +158,7 @@ private async Task VerifyDocumentHighlightsAsync(string input, DocumentHighlight var request = new DocumentHighlightParams() { TextDocument = new TextDocumentIdentifier() { Uri = document.CreateUri() }, - Position = new Position(lineIndex, characterIndex) + Position = position }; var result = await endpoint.GetTestAccessor().HandleRequestAsync(request, document, DisposalToken); @@ -172,7 +171,7 @@ private async Task VerifyDocumentHighlightsAsync(string input, DocumentHighlight Assert.NotNull(result); - var actual = TestFileMarkupParser.CreateTestFile(source, cursorPosition, result.SelectAsArray(h => h.Range.ToTextSpan(inputText))); + var actual = TestFileMarkupParser.CreateTestFile(source, cursorPosition, result.SelectAsArray(h => inputText.GetTextSpan(h.Range))); AssertEx.EqualOrDiff(input, actual); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostFoldingRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostFoldingRangeEndpointTest.cs index 2f8a9be3573..08ad6977496 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostFoldingRangeEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostFoldingRangeEndpointTest.cs @@ -225,14 +225,13 @@ private async Task VerifyFoldingRangesAsync(string input, string? fileKind = nul var htmlRanges = htmlSpans .Select(span => { - inputText.GetLineAndOffset(span.Start, out var startLine, out var startCharacter); - inputText.GetLineAndOffset(span.End, out var endLine, out var endCharacter); + var (start, end) = inputText.GetLinePositionSpan(span); return new FoldingRange() { - StartLine = startLine, - StartCharacter = startCharacter, - EndLine = endLine, - EndCharacter = endCharacter + StartLine = start.Line, + StartCharacter = start.Character, + EndLine = end.Line, + EndCharacter = end.Character }; }) .ToArray(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs index 2f100059fb8..cd2c7baddaa 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostLinkedEditingRangeEndpointTest.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.LinkedEditingRange; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -162,7 +161,6 @@ private async Task VerifyLinkedEditingRangeAsync(string input) TestFileMarkupParser.GetPositionAndSpans(input, out input, out int cursorPosition, out ImmutableArray spans); var document = CreateProjectAndRazorDocument(input); var sourceText = await document.GetTextAsync(DisposalToken); - sourceText.GetLineAndOffset(cursorPosition, out var lineIndex, out var characterIndex); var endpoint = new CohostLinkedEditingRangeEndpoint(RemoteServiceInvoker, LoggerFactory); @@ -172,11 +170,7 @@ private async Task VerifyLinkedEditingRangeAsync(string input) { Uri = document.CreateUri() }, - Position = new Position() - { - Line = lineIndex, - Character = characterIndex - } + Position = sourceText.GetPosition(cursorPosition) }; var result = await endpoint.GetTestAccessor().HandleRequestAsync(request, document, DisposalToken); @@ -189,7 +183,7 @@ private async Task VerifyLinkedEditingRangeAsync(string input) Assert.NotNull(result); Assert.Equal(LinkedEditingRangeHelper.WordPattern, result.WordPattern); - Assert.Equal(spans[0], result.Ranges[0].ToTextSpan(sourceText)); - Assert.Equal(spans[1], result.Ranges[1].ToTextSpan(sourceText)); + Assert.Equal(spans[0], sourceText.GetTextSpan(result.Ranges[0])); + Assert.Equal(spans[1], sourceText.GetTextSpan(result.Ranges[1])); } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSignatureHelpEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSignatureHelpEndpointTest.cs index 35c070ae769..276e1de71a1 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSignatureHelpEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSignatureHelpEndpointTest.cs @@ -5,8 +5,8 @@ using Microsoft.AspNetCore.Razor; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Settings; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.LanguageServices.Razor.LanguageClient.Cohost; using Microsoft.VisualStudio.Razor.Settings; @@ -93,7 +93,6 @@ private async Task VerifySignatureHelpAsync(string input, string expected, bool TestFileMarkupParser.GetPosition(input, out input, out var cursorPosition); var document = CreateProjectAndRazorDocument(input); var sourceText = await document.GetTextAsync(DisposalToken); - sourceText.GetLineAndOffset(cursorPosition, out var lineIndex, out var characterIndex); var clientSettingsManager = new ClientSettingsManager([], null, null); clientSettingsManager.Update(ClientCompletionSettings.Default with { AutoListParams = autoListParams }); @@ -113,11 +112,7 @@ private async Task VerifySignatureHelpAsync(string input, string expected, bool { Uri = document.CreateUri() }, - Position = new Position() - { - Line = lineIndex, - Character = characterIndex - }, + Position = sourceText.GetPosition(cursorPosition), Context = signatureHelpContext }; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostUriPresentationEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostUriPresentationEndpointTest.cs index 9136cb1e8ea..981e8f7a8b9 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostUriPresentationEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostUriPresentationEndpointTest.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.ExternalAccess.Razor; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Testing; using Microsoft.VisualStudio.LanguageServer.Protocol; using Xunit; @@ -62,7 +61,7 @@ The end. { Uri = FileUri("File1.razor.g.html") }, - Edits = [new() { NewText = htmlTag}] + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), htmlTag)] } } }, @@ -126,7 +125,7 @@ This is a Razor document. { Uri = FileUri("File1.razor.g.html") }, - Edits = [new() { NewText = htmlTag}] + Edits = [VsLspFactory.CreateTextEdit(position: (0, 0), htmlTag)] } } }, @@ -280,7 +279,7 @@ private async Task VerifyUriPresentationAsync(string input, Uri[] uris, string? { Uri = document.CreateUri() }, - Range = span.ToRange(sourceText), + Range = sourceText.GetRange(span), Uris = uris }; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpDocumentExcerptServiceTests.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpDocumentExcerptServiceTests.cs index 7a223d72e89..2b693754950 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpDocumentExcerptServiceTests.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/CSharpDocumentExcerptServiceTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.Workspaces; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.ExternalAccess.Razor; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Razor.DynamicFiles; using Xunit; using Xunit.Abstractions; @@ -39,7 +40,7 @@ public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp() #pragma warning disable CS0618 // Type or member is obsolete var excerptService = new CSharpDocumentExcerptService(); #pragma warning restore CS0618 // Type or member is obsolete - var mappedLinePositionSpan = razorSourceText.Lines.GetLinePositionSpan(primarySpan); + var mappedLinePositionSpan = razorSourceText.GetLinePositionSpan(primarySpan); // Act var options = RazorClassificationOptionsWrapper.Default; @@ -127,7 +128,7 @@ public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_Implic #pragma warning disable CS0618 // Type or member is obsolete var excerptService = new CSharpDocumentExcerptService(); #pragma warning restore CS0618 // Type or member is obsolete - var mappedLinePositionSpan = razorSourceText.Lines.GetLinePositionSpan(primarySpan); + var mappedLinePositionSpan = razorSourceText.GetLinePositionSpan(primarySpan); // Act var options = RazorClassificationOptionsWrapper.Default; @@ -173,7 +174,7 @@ public async Task TryGetExcerptInternalAsync_SingleLine_CanClassifyCSharp_Comple #pragma warning disable CS0618 // Type or member is obsolete var excerptService = new CSharpDocumentExcerptService(); #pragma warning restore CS0618 // Type or member is obsolete - var mappedLinePositionSpan = razorSourceText.Lines.GetLinePositionSpan(primarySpan); + var mappedLinePositionSpan = razorSourceText.GetLinePositionSpan(primarySpan); // Act var options = RazorClassificationOptionsWrapper.Default; @@ -220,7 +221,7 @@ public async Task TryGetExcerptInternalAsync_MultiLine_CanClassifyCSharp() #pragma warning disable CS0618 // Type or member is obsolete var excerptService = new CSharpDocumentExcerptService(); #pragma warning restore CS0618 // Type or member is obsolete - var mappedLinePositionSpan = razorSourceText.Lines.GetLinePositionSpan(primarySpan); + var mappedLinePositionSpan = razorSourceText.GetLinePositionSpan(primarySpan); // Act var options = RazorClassificationOptionsWrapper.Default; @@ -266,7 +267,7 @@ public async Task TryGetExcerptInternalAsync_MultiLine_Boundaries_CanClassifyCSh #pragma warning disable CS0618 // Type or member is obsolete var excerptService = new CSharpDocumentExcerptService(); #pragma warning restore CS0618 // Type or member is obsolete - var mappedLinePositionSpan = razorSourceText.Lines.GetLinePositionSpan(primarySpan); + var mappedLinePositionSpan = razorSourceText.GetLinePositionSpan(primarySpan); // Act var options = RazorClassificationOptionsWrapper.Default; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/DefaultRazorBreakpointResolverTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/DefaultRazorBreakpointResolverTest.cs index 162ff395e45..f52c195fd07 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/DefaultRazorBreakpointResolverTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/DefaultRazorBreakpointResolverTest.cs @@ -15,6 +15,7 @@ using Moq; using Xunit; using Xunit.Abstractions; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient.Debugging; @@ -131,11 +132,7 @@ public async Task TryResolveBreakpointRangeAsync_MappableCSharpBreakpointLocatio { // Arrange var hostDocumentPosition = GetPosition(ValidBreakpointCSharp, _hostTextbuffer); - var hostBreakpointRange = new Range() - { - Start = hostDocumentPosition, - End = new Position(hostDocumentPosition.Line, hostDocumentPosition.Character + ValidBreakpointCSharp.Length), - }; + var hostBreakpointRange = VsLspFactory.CreateSingleLineRange(start: hostDocumentPosition, length: ValidBreakpointCSharp.Length); var projectionProvider = new TestLSPBreakpointSpanProvider( _documentUri, new Dictionary() @@ -186,6 +183,6 @@ private static Position GetPosition(string content, ITextBuffer textBuffer) } var line = textBuffer.CurrentSnapshot.GetLineFromPosition(index); - return new Position(line.LineNumber, index - line.Start.Position); + return VsLspFactory.CreatePosition(line.LineNumber, index - line.Start.Position); } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/TestLSPBreakpointSpanProvider.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/TestLSPBreakpointSpanProvider.cs index 4c65bb170a1..b594365bdd2 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/TestLSPBreakpointSpanProvider.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/Debugging/TestLSPBreakpointSpanProvider.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Threading; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient.Debugging; diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProviderTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProviderTest.cs index 79adf17c94f..0efc73d8dbf 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProviderTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/DocumentMapping/DefaultLSPDocumentMappingProviderTest.cs @@ -47,13 +47,7 @@ public async Task RazorMapToDocumentRangeAsync_InvokesLanguageServer() var response = new RazorMapToDocumentRangesResponse() { - Ranges = new[] { - new Range() - { - Start = new Position(1, 1), - End = new Position(3, 3), - } - }, + Ranges = [VsLspFactory.CreateRange(1, 1, 3, 3)], HostDocumentVersion = 1 }; var requestInvoker = new Mock(MockBehavior.Strict); @@ -67,11 +61,7 @@ public async Task RazorMapToDocumentRangeAsync_InvokesLanguageServer() .ReturnsAsync(new ReinvocationResponse("TestLanguageClient", response)); var mappingProvider = new DefaultLSPDocumentMappingProvider(requestInvoker.Object, _documentManager); - var projectedRange = new Range() - { - Start = new Position(10, 10), - End = new Position(15, 15) - }; + var projectedRange = VsLspFactory.CreateRange(10, 10, 15, 15); // Act var result = await mappingProvider.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, uri, new[] { projectedRange }, DisposalToken); @@ -80,7 +70,7 @@ public async Task RazorMapToDocumentRangeAsync_InvokesLanguageServer() Assert.NotNull(result); Assert.Equal(1, result.HostDocumentVersion); var actualRange = result.Ranges[0]; - Assert.Equal(new Position(1, 1), actualRange.Start); - Assert.Equal(new Position(3, 3), actualRange.End); + Assert.Equal(VsLspFactory.CreatePosition(1, 1), actualRange.Start); + Assert.Equal(VsLspFactory.CreatePosition(3, 3), actualRange.End); } } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs index 5fafd0e5df1..99132c4935c 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Razor.Workspaces.Protocol.SemanticTokens; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.Cohost; @@ -215,7 +214,7 @@ public async Task ProvideCodeActionsAsync_CannotLookupDocument_ReturnsNullAsync( { Uri = new Uri("C:/path/to/file.razor") }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() } }; @@ -296,7 +295,7 @@ async IAsyncEnumerable> { Uri = testDocUri }, - Range = new Range(), + Range = VsLspFactory.DefaultRange, Context = new VSInternalCodeActionContext() } }; @@ -421,7 +420,7 @@ public async Task ProvideSemanticTokensAsync_CannotLookupDocument_ReturnsNullAsy Uri = new Uri("C:/path/to/file.razor") }, requiredHostDocumentVersion: 1, - ranges: new[] { new Range() }, + ranges: [VsLspFactory.DefaultRange], correlationId: Guid.Empty); // Act @@ -470,7 +469,7 @@ public async Task ProvideSemanticTokensAsync_CannotLookupVirtualDocument_Returns Uri = new Uri("C:/path/to/file.razor") }, requiredHostDocumentVersion: 0, - ranges: new[] { new Range() }, + ranges: [VsLspFactory.DefaultRange], correlationId: Guid.Empty); // Act @@ -547,7 +546,7 @@ public async Task ProvideSemanticTokensAsync_ContainsRange_ReturnsSemanticTokens Uri = new Uri("C:/path/to%20-%20project/file.razor") }, requiredHostDocumentVersion: 0, - ranges: new[] { new Range() { Start = It.IsAny(), End = It.IsAny() } }, + ranges: [VsLspFactory.DefaultRange], correlationId: Guid.Empty); // Act @@ -625,7 +624,7 @@ public async Task ProvideSemanticTokensAsync_EmptyRange_ReturnsNoSemanticTokens( Uri = new Uri("C:/path/to%20-%20project/file.razor") }, requiredHostDocumentVersion: 0, - ranges: new[] { new Range() }, + ranges: [VsLspFactory.DefaultRange], correlationId: Guid.Empty); var expectedResults = new ProvideSemanticTokensResponse(null, documentVersion); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorLSPSpanMappingServiceTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorLSPSpanMappingServiceTest.cs index 8ae26a27ebe..cae25378834 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorLSPSpanMappingServiceTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorLSPSpanMappingServiceTest.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Razor.Test.Common.Editor; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.DocumentMapping; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -19,6 +18,7 @@ using Moq; using Xunit; using Xunit.Abstractions; +using Range = Microsoft.VisualStudio.LanguageServer.Protocol.Range; namespace Microsoft.VisualStudio.Razor.LanguageClient; @@ -63,17 +63,13 @@ public async Task MapSpans_WithinRange_ReturnsMapping() var textSnapshot = new StringTextSnapshot(s_mockGeneratedContent, 1); - var textSpanAsRange = textSpan.ToRange(_sourceTextGenerated); - var mappedRange = new Range() - { - Start = new Position(2, 1), - End = new Position(2, 11) - }; + var textSpanAsRange = _sourceTextGenerated.GetRange(textSpan); + var mappedRange = VsLspFactory.CreateSingleLineRange(2, character: 1, length: 10); var documentMappingProvider = new Mock(MockBehavior.Strict); var mappingResult = new RazorMapToDocumentRangesResponse() { - Ranges = new Range[] { mappedRange } + Ranges = [mappedRange] }; documentMappingProvider.Setup(dmp => dmp.MapToDocumentRangesAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((languageKind, uri, ranges, ct) => @@ -87,8 +83,8 @@ public async Task MapSpans_WithinRange_ReturnsMapping() var service = new RazorLSPSpanMappingService(documentMappingProvider.Object, documentSnapshot.Object, textSnapshot); - var expectedSpan = mappedRange.AsTextSpan(_sourceTextRazor); - var expectedLinePosition = _sourceTextRazor.Lines.GetLinePositionSpan(expectedSpan); + var expectedSpan = _sourceTextRazor.GetTextSpan(mappedRange); + var expectedLinePosition = _sourceTextRazor.GetLinePositionSpan(expectedSpan); var expectedFilePath = _mockDocumentUri.LocalPath; var expectedResult = (expectedFilePath, expectedLinePosition, expectedSpan); @@ -114,7 +110,7 @@ public async Task MapSpans_OutsideRange_ReturnsEmpty() var textSnapshot = new StringTextSnapshot(s_mockGeneratedContent, 1); - var textSpanAsRange = textSpan.ToRange(_sourceTextGenerated); + var textSpanAsRange = _sourceTextGenerated.GetRange(textSpan); var documentMappingProvider = new Mock(MockBehavior.Strict); documentMappingProvider.Setup(dmp => dmp.MapToDocumentRangesAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) @@ -142,7 +138,7 @@ public void MapSpans_GetMappedSpanResults_MappingErrorReturnsDefaultMappedSpan() { // Arrange var sourceTextRazor = SourceText.From(""); - var response = new RazorMapToDocumentRangesResponse { Ranges = new Range[] { RangeExtensions.UndefinedRange } }; + var response = new RazorMapToDocumentRangesResponse { Ranges = new Range[] { VsLspFactory.UndefinedRange } }; // Act var results = RazorLSPSpanMappingService.GetMappedSpanResults(_mockDocumentUri.LocalPath, sourceTextRazor, response); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestDocumentManager.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestDocumentManager.cs index cb13040f4e8..9637feecd45 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestDocumentManager.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestDocumentManager.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.LanguageServer; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Text; namespace Microsoft.VisualStudio.Razor.LanguageClient; @@ -72,11 +73,7 @@ private void UpdateCSharpServerDocument(IReadOnlyList changes, Virt var rangesAndTexts = changes.Select(c => { GetLinesAndOffsets(virtualSourceText, c.OldSpan, out var startLine, out var startCharacter, out var endLine, out var endCharacter); - var range = new Range - { - Start = new LanguageServer.Protocol.Position { Line = startLine, Character = startCharacter }, - End = new LanguageServer.Protocol.Position { Line = endLine, Character = endCharacter } - }; + var range = VsLspFactory.CreateRange(startLine, startCharacter, endLine, endCharacter); return (range, c.NewText); }).ToArray(); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestRazorLSPSpanMappingService.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestRazorLSPSpanMappingService.cs index bc557ce200d..3b46d91e9c7 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestRazorLSPSpanMappingService.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/TestRazorLSPSpanMappingService.cs @@ -10,8 +10,8 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.ExternalAccess.Razor; using Microsoft.CodeAnalysis.Razor.Protocol; -using Microsoft.CodeAnalysis.Razor.Workspaces; using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.LanguageClient.DocumentMapping; namespace Microsoft.VisualStudio.Razor.LanguageClient; @@ -40,7 +40,7 @@ public TestRazorLSPSpanMappingService( public async Task> MapSpansAsync(Document document, IEnumerable spans, CancellationToken cancellationToken) { - var projectedRanges = spans.Select(span => span.ToRange(_csharpSourceText)).ToArray(); + var projectedRanges = spans.Select(_csharpSourceText.GetRange).ToArray(); var mappedResult = await _mappingProvider.MapToDocumentRangesAsync( RazorLanguageKind.CSharp, _razorUri, projectedRanges, _cancellationToken); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj index 441ecb802fe..266d9132319 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj @@ -9,10 +9,6 @@ true - - - - Shared\%(RecursiveDir)%(FileName)%(Extension) diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/RazorLanguageService_IVsLanguageDebugInfoTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/RazorLanguageService_IVsLanguageDebugInfoTest.cs index 90673d7aa00..4dd8aa8e590 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/RazorLanguageService_IVsLanguageDebugInfoTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/RazorLanguageService_IVsLanguageDebugInfoTest.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.AspNetCore.Razor.Test.Common.Editor; using Microsoft.VisualStudio.Editor; +using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.Debugging; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.TextManager.Interop; @@ -16,7 +17,6 @@ using Moq; using Xunit; using Xunit.Abstractions; -using Position = Microsoft.VisualStudio.LanguageServer.Protocol.Position; namespace Microsoft.VisualStudio.Razor; @@ -69,11 +69,7 @@ public void ValidateBreakpointLocation_NullBreakpointRange_ReturnsEFail() public void ValidateBreakpointLocation_ValidBreakpointRange_ReturnsSOK() { // Arrange - var breakpointRange = new Range() - { - Start = new Position(2, 4), - End = new Position(3, 5), - }; + var breakpointRange = VsLspFactory.CreateRange(2, 4, 3, 5); var breakpointResolver = Mock.Of(resolver => resolver.TryResolveBreakpointRangeAsync(It.IsAny(), 0, 0, It.IsAny()) == System.Threading.Tasks.Task.FromResult(breakpointRange), MockBehavior.Strict); var languageService = CreateLanguageServiceWith(breakpointResolver);