public override async Task <RazorDiagnosticsResponse?> TranslateAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Diagnostic[] diagnostics, CancellationToken cancellationToken) { if (!_documentManager.TryGetDocument(razorDocumentUri, out var documentSnapshot)) { return(new RazorDiagnosticsResponse() { Diagnostics = Array.Empty <Diagnostic>(), }); } var diagnosticsParams = new RazorDiagnosticsParams() { Kind = languageKind, RazorDocumentUri = razorDocumentUri, Diagnostics = diagnostics }; var response = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorDiagnosticsParams, RazorDiagnosticsResponse>( documentSnapshot.Snapshot.TextBuffer, LanguageServerConstants.RazorTranslateDiagnosticsEndpoint, RazorLSPConstants.RazorLanguageServerName, diagnosticsParams, cancellationToken).ConfigureAwait(false); if (!ReinvocationResponseHelper.TryExtractResultOrLog(response, _logger, RazorLSPConstants.RazorLanguageServerName, out var result)) { return(null); } return(result); }
public override async Task <RazorDiagnosticsResponse> TranslateAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Diagnostic[] diagnostics, CancellationToken cancellationToken) { if (razorDocumentUri is null) { throw new ArgumentNullException(nameof(razorDocumentUri)); } if (diagnostics is null) { throw new ArgumentNullException(nameof(diagnostics)); } var diagnosticsParams = new RazorDiagnosticsParams() { Kind = languageKind, RazorDocumentUri = razorDocumentUri, Diagnostics = diagnostics }; var diagnosticResponse = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorDiagnosticsParams, RazorDiagnosticsResponse>( LanguageServerConstants.RazorTranslateDiagnosticsEndpoint, RazorLSPConstants.RazorLSPContentTypeName, diagnosticsParams, cancellationToken).ConfigureAwait(false); return(diagnosticResponse); }
// Internal for testing internal bool TriggerAppliesToProjection(CompletionContext context, RazorLanguageKind languageKind) { if (languageKind == RazorLanguageKind.Razor) { // We don't handle any type of triggers in Razor pieces of the document return(false); } if (context.TriggerKind != CompletionTriggerKind.TriggerCharacter) { // Not a trigger character completion, allow it. return(true); } if (!AllTriggerCharacters.Contains(context.TriggerCharacter)) { // This is an auto-invoked completion from the VS LSP platform. Completions are automatically invoked upon typing identifiers // and are represented as CompletionTriggerKind.TriggerCharacter and have a trigger character that we have not registered for. return(true); } if (IsApplicableTriggerCharacter(context.TriggerCharacter, languageKind)) { // Trigger character is associated with the langauge at the current cursor position return(true); } // We were triggered but the trigger character doesn't make sense for the current cursor position. Bail. return(false); }
private CompletionContext RewriteContext(CompletionContext context, RazorLanguageKind languageKind) { if (context.TriggerKind != CompletionTriggerKind.TriggerCharacter) { // Non-triggered based completion, the existing context is valid; return(context); } if (languageKind == RazorLanguageKind.CSharp && CSharpTriggerCharacters.Contains(context.TriggerCharacter)) { // C# trigger character for C# content return(context); } if (languageKind == RazorLanguageKind.Html && HtmlTriggerCharacters.Contains(context.TriggerCharacter)) { // HTML trigger character for HTML content return(context); } // Trigger character not associated with the current langauge. Transform the context into an invoked context. var rewrittenContext = new CompletionContext() { TriggerKind = CompletionTriggerKind.Invoked }; return(rewrittenContext); }
public override async Task <TextEdit[]> ApplyFormattedEditsAsync( DocumentUri uri, DocumentSnapshot documentSnapshot, RazorLanguageKind kind, TextEdit[] formattedEdits, FormattingOptions options, CancellationToken cancellationToken, bool bypassValidationPasses = false) { if (kind == RazorLanguageKind.Html) { // We don't support formatting HTML edits yet. return(formattedEdits); } var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); using var context = FormattingContext.Create(uri, documentSnapshot, codeDocument, options, isFormatOnType: true); var result = new FormattingResult(formattedEdits, kind); foreach (var pass in _formattingPasses) { if (pass.IsValidationPass && bypassValidationPasses) { continue; } cancellationToken.ThrowIfCancellationRequested(); result = await pass.ExecuteAsync(context, result, cancellationToken); } return(result.Edits); }
public abstract Task <TextEdit[]> ApplyFormattedEditsAsync( DocumentUri uri, DocumentSnapshot documentSnapshot, RazorLanguageKind kind, TextEdit[] formattedEdits, FormattingOptions options, CancellationToken cancellationToken);
public async override Task <RazorMapToDocumentRangesResponse> MapToDocumentRangesAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Range[] projectedRanges, LanguageServerMappingBehavior mappingBehavior, CancellationToken cancellationToken) { if (razorDocumentUri is null) { throw new ArgumentNullException(nameof(razorDocumentUri)); } if (projectedRanges is null) { throw new ArgumentNullException(nameof(projectedRanges)); } var mapToDocumentRangeParams = new RazorMapToDocumentRangesParams() { Kind = languageKind, RazorDocumentUri = razorDocumentUri, ProjectedRanges = projectedRanges, MappingBehavior = mappingBehavior, }; var documentMappingResponse = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorMapToDocumentRangesParams, RazorMapToDocumentRangesResponse>( LanguageServerConstants.RazorMapToDocumentRangesEndpoint, RazorLSPConstants.RazorLSPContentTypeName, mapToDocumentRangeParams, cancellationToken).ConfigureAwait(false); return(documentMappingResponse); }
protected override async Task <WorkspaceEdit?> TryGetRazorWorkspaceEditAsync(RazorLanguageKind languageKind, UriPresentationParams request, CancellationToken cancellationToken) { if (languageKind is not RazorLanguageKind.Html) { // We don't do anything for HTML return(null); } if (request.Uris is null || request.Uris.Length == 0) { _logger.LogInformation($"No URIs were included in the request?"); return(null); } // We only want to handle requests for a single .razor file, but when there are files nested under a .razor // file (for example, Goo.razor.css, Goo.razor.cs etc.) then we'll get all of those files as well, when the user // thinks they're just dragging the parent one, so we have to be a little bit clever with the filter here var razorFileUri = request.Uris.Last(); var fileName = Path.GetFileName(razorFileUri.GetAbsoluteOrUNCPath()); if (!fileName.EndsWith(".razor", FilePathComparison.Instance)) { _logger.LogInformation("Last file in the drop was not a single razor file URI."); return(null); } if (request.Uris.Any(uri => !Path.GetFileName(uri.GetAbsoluteOrUNCPath()).StartsWith(fileName, FilePathComparison.Instance))) { _logger.LogInformation("One or more URIs were not a child file of the main .razor file."); return(null); } var componentTagText = await TryGetComponentTagAsync(razorFileUri, cancellationToken).ConfigureAwait(false); if (componentTagText is null) { return(null); } return(new WorkspaceEdit { DocumentChanges = new TextDocumentEdit[] { new TextDocumentEdit { TextDocument = new() { Uri = request.TextDocument.Uri }, Edits = new[] { new TextEdit { NewText = componentTagText, Range = request.Range } } } } });
public abstract Task <TextEdit[]> ApplyFormattedEditsAsync( DocumentUri uri, DocumentSnapshot documentSnapshot, RazorLanguageKind kind, TextEdit[] formattedEdits, FormattingOptions options, CancellationToken cancellationToken, bool bypassValidationPasses = false, bool collapseEdits = false);
public static string ToContainedLanguageServerName(this RazorLanguageKind razorLanguageKind) { return(razorLanguageKind switch { RazorLanguageKind.CSharp => RazorLSPConstants.RazorCSharpLanguageServerName, RazorLanguageKind.Html => RazorLSPConstants.HtmlLanguageServerName, RazorLanguageKind.Razor => RazorLSPConstants.RazorLanguageServerName, _ => throw new NotImplementedException("A RazorLanguageKind did not have a corresponding ClientName"), });
public abstract Task <TextEdit[]> FormatOnTypeAsync( DocumentUri uri, DocumentSnapshot documentSnapshot, RazorLanguageKind kind, TextEdit[] formattedEdits, FormattingOptions options, int hostDocumentIndex, char triggerCharacter, CancellationToken cancellationToken);
public override async Task <TextEdit[]> ApplyFormattedEditsAsync( DocumentUri uri, DocumentSnapshot documentSnapshot, RazorLanguageKind kind, TextEdit[] formattedEdits, FormattingOptions options, CancellationToken cancellationToken, bool bypassValidationPasses = false, bool collapseEdits = false) { if (kind == RazorLanguageKind.Html) { // We don't support formatting HTML edits yet. return(formattedEdits); } // If we only received a single edit, let's always return a single edit back. // Otherwise, merge only if explicitly asked. collapseEdits |= formattedEdits.Length == 1; var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); using var context = FormattingContext.Create(uri, documentSnapshot, codeDocument, options, _workspaceFactory, isFormatOnType: true); var result = new FormattingResult(formattedEdits, kind); foreach (var pass in _formattingPasses) { if (pass.IsValidationPass && bypassValidationPasses) { continue; } cancellationToken.ThrowIfCancellationRequested(); result = await pass.ExecuteAsync(context, result, cancellationToken); } var originalText = context.SourceText; var edits = result.Edits; if (collapseEdits) { var collapsedEdit = MergeEdits(result.Edits, originalText); edits = new[] { collapsedEdit }; } // Make sure the edits actually change something, or its not worth responding var textChanges = edits.Select(e => e.AsTextChange(originalText)); var changedText = originalText.WithChanges(textChanges); if (changedText.ContentEquals(originalText)) { return(Array.Empty <TextEdit>()); } return(edits); }
public FormattingResult(TextEdit[] edits, RazorLanguageKind kind = RazorLanguageKind.Razor) { if (edits is null) { throw new ArgumentNullException(nameof(edits)); } Edits = edits; Kind = kind; }
public override Task <RazorMapToDocumentRangesResponse> MapToDocumentRangesAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Range[] projectedRanges, LanguageServerMappingBehavior mappingBehavior, CancellationToken cancellationToken) { _mappings.TryGetValue(projectedRanges[0], out var response); return(Task.FromResult(response)); }
private static bool IsApplicableTriggerCharacter(string triggerCharacter, RazorLanguageKind languageKind) { if (languageKind == RazorLanguageKind.CSharp) { return(CSharpTriggerCharacters.Contains(triggerCharacter)); } else if (languageKind == RazorLanguageKind.Html) { return(HtmlTriggerCharacters.Contains(triggerCharacter)); } // Unknown trigger character. return(false); }
public override async Task <TextEdit[]> ApplyFormattedEditsAsync( DocumentUri uri, DocumentSnapshot documentSnapshot, RazorLanguageKind kind, TextEdit[] formattedEdits, FormattingOptions options, CancellationToken cancellationToken, bool bypassValidationPasses = false, bool collapseEdits = false) { if (kind == RazorLanguageKind.Html) { // We don't support formatting HTML edits yet. return(formattedEdits); } // If we only received a single edit, let's always return a single edit back. // Otherwise, merge only if explicitly asked. collapseEdits |= formattedEdits.Length == 1; var codeDocument = await documentSnapshot.GetGeneratedOutputAsync(); using var context = FormattingContext.Create(uri, documentSnapshot, codeDocument, options, isFormatOnType: true); var result = new FormattingResult(formattedEdits, kind); foreach (var pass in _formattingPasses) { if (pass.IsValidationPass && bypassValidationPasses) { continue; } cancellationToken.ThrowIfCancellationRequested(); result = await pass.ExecuteAsync(context, result, cancellationToken); } var edits = result.Edits; if (collapseEdits) { var collapsedEdit = MergeEdits(result.Edits, context.SourceText); edits = new[] { collapsedEdit }; } return(edits); }
private static bool IsApplicableTriggerCharacter(string triggerCharacter, RazorLanguageKind languageKind) { if (RazorTriggerCharacters.Contains(triggerCharacter)) { // Razor trigger characters always transition into either C# or HTML, always note as "applicable". return(true); } else if (languageKind == RazorLanguageKind.CSharp) { return(CSharpTriggerCharacters.Contains(triggerCharacter)); } else if (languageKind == RazorLanguageKind.Html) { return(HtmlTriggerCharacters.Contains(triggerCharacter)); } // Unknown trigger character. return(false); }
public async override Task <RazorMapToDocumentRangesResponse?> MapToDocumentRangesAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Range[] projectedRanges, LanguageServerMappingBehavior mappingBehavior, CancellationToken cancellationToken) { if (razorDocumentUri is null) { throw new ArgumentNullException(nameof(razorDocumentUri)); } if (projectedRanges is null) { throw new ArgumentNullException(nameof(projectedRanges)); } var mapToDocumentRangeParams = new RazorMapToDocumentRangesParams() { Kind = languageKind, RazorDocumentUri = razorDocumentUri, ProjectedRanges = projectedRanges, MappingBehavior = mappingBehavior, }; if (!_lazyDocumentManager.Value.TryGetDocument(razorDocumentUri, out var documentSnapshot)) { return(null); } var documentMappingResponse = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorMapToDocumentRangesParams, RazorMapToDocumentRangesResponse>( documentSnapshot.Snapshot.TextBuffer, LanguageServerConstants.RazorMapToDocumentRangesEndpoint, RazorLSPConstants.RazorLanguageServerName, CheckRazorRangeMappingCapability, mapToDocumentRangeParams, cancellationToken).ConfigureAwait(false); return(documentMappingResponse?.Response); }
// Internal for testing internal bool TriggerAppliesToProjection(CompletionContext context, RazorLanguageKind languageKind) { if (languageKind == RazorLanguageKind.Razor) { // We don't handle any type of triggers in Razor pieces of the document return(false); } if (context.TriggerKind != CompletionTriggerKind.TriggerCharacter) { // Not a trigger character completion, allow it. return(true); } if (!AllTriggerCharacters.Contains(context.TriggerCharacter)) { // This is an auto-invoked completion from the VS LSP platform. Completions are automatically invoked upon typing identifiers // and are represented as CompletionTriggerKind.TriggerCharacter and have a trigger character that we have not registered for. return(true); } if (context.TriggerCharacter == "(") { // This is a special case. // We added `(` as a trigger character to workaround problems with Razor explicit expressions. // Example - https://github.com/dotnet/aspnetcore/issues/21154 // But we don't really want to show a completion box every time a `(` is typed. return(false); } if (IsApplicableTriggerCharacter(context.TriggerCharacter, languageKind)) { // Trigger character is associated with the langauge at the current cursor position return(true); } // We were triggered but the trigger character doesn't make sense for the current cursor position. Bail. return(false); }
public abstract Task <RazorMapToDocumentRangesResponse> MapToDocumentRangesAsync(RazorLanguageKind languageKind, Uri razorDocumentUri, Range[] projectedRanges, LanguageServerMappingBehavior mappingBehavior, CancellationToken cancellationToken);
private LSPDocumentMappingProvider GetDocumentMappingProvider(Range expectedRange, int expectedVersion, RazorLanguageKind languageKind) { var remappingResult = new RazorMapToDocumentRangesResponse() { Ranges = new[] { expectedRange }, HostDocumentVersion = expectedVersion }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict); documentMappingProvider.Setup(d => d.MapToDocumentRangesAsync(languageKind, Uri, It.IsAny <Range[]>(), It.IsAny <CancellationToken>())). Returns(Task.FromResult(remappingResult)); return(documentMappingProvider.Object); }
// TODO; HTML filtering blocked on https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1257401 static bool CanDiagnosticBeFiltered(RazorLanguageKind kind, Diagnostic d) { return(kind == RazorLanguageKind.CSharp ? CanCSharpDiagnosticBeFiltered(d) : CanHTMLDiagnosticBeFiltered(d)); }
public override Task <RazorMapToDocumentRangesResponse> MapToDocumentRangesAsync(RazorLanguageKind languageKind, Uri razorDocumentUri, Range[] projectedRanges, CancellationToken cancellationToken) => MapToDocumentRangesAsync(languageKind, razorDocumentUri, projectedRanges, LanguageServerMappingBehavior.Strict, cancellationToken);
public override Task <RazorMapToDocumentRangesResponse> MapToDocumentRangesAsync(RazorLanguageKind languageKind, Uri razorDocumentUri, LanguageServer.Protocol.Range[] projectedRanges, LanguageServerMappingBehavior mappingBehavior, CancellationToken cancellationToken) => throw new NotImplementedException();
public abstract Task <RazorDiagnosticsResponse> TranslateAsync( RazorLanguageKind languageKind, Uri razorDocumentUri, Diagnostic[] diagnostics, CancellationToken cancellationToken);
protected override Task <WorkspaceEdit?> TryGetRazorWorkspaceEditAsync(RazorLanguageKind languageKind, TextPresentationParams request, CancellationToken cancellationToken) { // We don't do anything special with text return(Task.FromResult <WorkspaceEdit?>(null)); }
public static string ToContainedLanguageContentType(this RazorLanguageKind razorLanguageKind) => razorLanguageKind == RazorLanguageKind.CSharp ? RazorLSPConstants.CSharpContentTypeName : RazorLSPConstants.HtmlLSPDelegationContentTypeName;
protected TextEdit[] RemapTextEdits(RazorCodeDocument codeDocument, TextEdit[] projectedTextEdits, RazorLanguageKind projectedKind) { if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (projectedTextEdits is null) { throw new ArgumentNullException(nameof(projectedTextEdits)); } if (projectedKind != RazorLanguageKind.CSharp) { // Non C# projections map directly to Razor. No need to remap. return(projectedTextEdits); } var edits = new List <TextEdit>(); for (var i = 0; i < projectedTextEdits.Length; i++) { var projectedRange = projectedTextEdits[i].Range; if (codeDocument.IsUnsupported() || !_documentMappingService.TryMapFromProjectedDocumentRange(codeDocument, projectedRange, out var originalRange)) { // Can't map range. Discard this edit. continue; } var edit = new TextEdit() { Range = originalRange, NewText = projectedTextEdits[i].NewText }; edits.Add(edit); } return(edits.ToArray()); }
public abstract Task <RazorMapToDocumentRangeResponse> MapToDocumentRangeAsync(RazorLanguageKind languageKind, Uri razorDocumentUri, Range projectedRange, CancellationToken cancellationToken);
protected TextEdit[] RemapTextEdits(RazorCodeDocument codeDocument, TextEdit[] projectedTextEdits, RazorLanguageKind projectedKind) { if (codeDocument is null) { throw new ArgumentNullException(nameof(codeDocument)); } if (projectedTextEdits is null) { throw new ArgumentNullException(nameof(projectedTextEdits)); } if (projectedKind != RazorLanguageKind.CSharp) { // Non C# projections map directly to Razor. No need to remap. return(projectedTextEdits); } if (codeDocument.IsUnsupported()) { return(Array.Empty <TextEdit>()); } var edits = DocumentMappingService.GetProjectedDocumentEdits(codeDocument, projectedTextEdits); return(edits); }