| File: Utils\MarkupHelpers.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Cli.Interaction; using Spectre.Console; namespace Aspire.Cli.Utils; /// <summary> /// Provides helpers for building Spectre.Console markup strings. /// </summary> internal static class MarkupHelpers { /// <summary> /// Builds a clickable link markup string when the console supports links, /// otherwise returns a plain-text fallback. /// </summary> public static string SafeLink(IInteractionService interactionService, string link, string? title = null) { return SafeLink(interactionService.SupportsLinks, link, title); } /// <summary> /// Builds a clickable link markup string when the console supports links, /// otherwise returns a plain-text fallback. /// </summary> public static string SafeLink(bool supportsLinks, string link, string? title = null) { var noTitle = title is null || title == link; link = link.EscapeMarkup(); title = title?.EscapeMarkup(); if (supportsLinks) { return noTitle ? $"[link]{link}[/]" : $"[link={link}]{title}[/]"; } return noTitle ? link : $"{title} ({link})"; } /// <summary> /// Builds a clickable file-link markup string for the specified file path /// when the console supports links, otherwise returns a plain-text fallback. /// The displayed text is the original <paramref name="filePath"/> and the /// link target is a <c>file://</c> URI built from the absolute path. /// </summary> public static string SafeFileLink(IInteractionService interactionService, string filePath) { return SafeFileLink(interactionService.SupportsLinks, filePath); } /// <summary> /// Builds a clickable file-link markup string for the specified file path /// when the console supports links, otherwise returns a plain-text fallback. /// The displayed text is the original <paramref name="filePath"/> and the /// link target is a <c>file://</c> URI built from the absolute path. /// </summary> public static string SafeFileLink(bool supportsLinks, string filePath) { return SafeFileLink(supportsLinks, filePath, displayName: null); } /// <summary> /// Builds a clickable file-link markup string for the specified file path /// when the console supports links, otherwise returns a plain-text fallback. /// The displayed text is <paramref name="displayName"/> (or the full path when /// <see langword="null"/>). If the path cannot be resolved to a valid URI /// (e.g. it came from an external process and is malformed), the display name /// is returned as escaped plain text. /// </summary> public static string SafeFileLink(IInteractionService interactionService, string filePath, string? displayName) { return SafeFileLink(interactionService.SupportsLinks, filePath, displayName); } /// <summary> /// Builds a clickable file-link markup string for the specified file path /// when the console supports links, otherwise returns a plain-text fallback. /// The displayed text is <paramref name="displayName"/> (or the full path when /// <see langword="null"/>). If the path cannot be resolved to a valid URI /// (e.g. it came from an external process and is malformed), the display name /// is returned as escaped plain text. /// </summary> public static string SafeFileLink(bool supportsLinks, string filePath, string? displayName) { if (string.IsNullOrEmpty(filePath)) { return string.Empty; } displayName ??= filePath; if (!supportsLinks) { return displayName.EscapeMarkup(); } try { var fileUri = new Uri(Path.GetFullPath(filePath)).AbsoluteUri; return SafeLink(supportsLinks: true, fileUri, displayName); } catch (Exception) { // The path may come from an external process (e.g. via backchannel) and // could be malformed. Fall back to plain escaped text so the error-display // path in BaseCommand doesn't throw and mask the original failure. return displayName.EscapeMarkup(); } } }