Patrik Svensson 504746c5dc Add link support for supported terminals
Also refactors the code quite a bit, to make it a bit more
easier to add features like this in the future.

Closes #75
2020-09-11 17:44:56 +02:00

215 lines
7.2 KiB
C#

using System;
using System.Diagnostics.CodeAnalysis;
using Spectre.Console.Internal;
namespace Spectre.Console
{
/// <summary>
/// Represents color and text decoration.
/// </summary>
public sealed class Style : IEquatable<Style>
{
/// <summary>
/// Gets the foreground color.
/// </summary>
public Color Foreground { get; }
/// <summary>
/// Gets the background color.
/// </summary>
public Color Background { get; }
/// <summary>
/// Gets the text decoration.
/// </summary>
public Decoration Decoration { get; }
/// <summary>
/// Gets the link.
/// </summary>
public string? Link { get; }
/// <summary>
/// Gets an <see cref="Style"/> with the
/// default colors and without text decoration.
/// </summary>
public static Style Plain { get; } = new Style();
private Style()
: this(null, null, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Style"/> class.
/// </summary>
/// <param name="foreground">The foreground color.</param>
/// <param name="background">The background color.</param>
/// <param name="decoration">The text decoration.</param>
/// <param name="link">The link.</param>
public Style(Color? foreground = null, Color? background = null, Decoration? decoration = null, string? link = null)
{
Foreground = foreground ?? Color.Default;
Background = background ?? Color.Default;
Decoration = decoration ?? Decoration.None;
Link = link;
}
/// <summary>
/// Creates a new style from the specified foreground color.
/// </summary>
/// <param name="color">The foreground color.</param>
/// <returns>A new <see cref="Style"/> with the specified foreground color.</returns>
public static Style WithForeground(Color color)
{
return new Style(foreground: color);
}
/// <summary>
/// Creates a new style from the specified background color.
/// </summary>
/// <param name="color">The background color.</param>
/// <returns>A new <see cref="Style"/> with the specified background color.</returns>
public static Style WithBackground(Color color)
{
return new Style(background: color);
}
/// <summary>
/// Creates a new style from the specified text decoration.
/// </summary>
/// <param name="decoration">The text decoration.</param>
/// <returns>A new <see cref="Style"/> with the specified text decoration.</returns>
public static Style WithDecoration(Decoration decoration)
{
return new Style(decoration: decoration);
}
/// <summary>
/// Creates a new style from the specified link.
/// </summary>
/// <param name="link">The link.</param>
/// <returns>A new <see cref="Style"/> with the specified link.</returns>
public static Style WithLink(string link)
{
return new Style(link: link);
}
/// <summary>
/// Creates a copy of the current <see cref="Style"/>.
/// </summary>
/// <returns>A copy of the current <see cref="Style"/>.</returns>
public Style Clone()
{
return new Style(Foreground, Background, Decoration, Link);
}
/// <summary>
/// Combines this style with another one.
/// </summary>
/// <param name="other">The item to combine with this.</param>
/// <returns>A new style representing a combination of this and the other one.</returns>
public Style Combine(Style other)
{
if (other is null)
{
throw new ArgumentNullException(nameof(other));
}
var foreground = Foreground;
if (!other.Foreground.IsDefault)
{
foreground = other.Foreground;
}
var background = Background;
if (!other.Background.IsDefault)
{
background = other.Background;
}
var link = Link;
if (!string.IsNullOrWhiteSpace(other.Link))
{
link = other.Link;
}
return new Style(foreground, background, Decoration | other.Decoration, link);
}
/// <summary>
/// Implicitly converts <see cref="string"/> into a <see cref="Style"/>.
/// </summary>
/// <param name="style">The style string.</param>
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates")]
public static explicit operator Style(string style)
{
return Parse(style);
}
/// <summary>
/// Converts the string representation of a style to its <see cref="Style"/> equivalent.
/// </summary>
/// <param name="text">A string containing a style to parse.</param>
/// <returns>A <see cref="Style"/> equivalent of the text contained in <paramref name="text"/>.</returns>
public static Style Parse(string text)
{
return StyleParser.Parse(text);
}
/// <summary>
/// Converts the string representation of a style to its <see cref="Style"/> equivalent.
/// A return value indicates whether the operation succeeded.
/// </summary>
/// <param name="text">A string containing a style to parse.</param>
/// <param name="result">
/// When this method returns, contains the <see cref="Style"/> equivalent of the text contained in <paramref name="text"/>,
/// if the conversion succeeded, or <c>null</c> if the conversion failed.
/// </param>
/// <returns><c>true</c> if s was converted successfully; otherwise, <c>false</c>.</returns>
public static bool TryParse(string text, out Style? result)
{
return StyleParser.TryParse(text, out result);
}
/// <inheritdoc/>
public override int GetHashCode()
{
unchecked
{
var hash = (int)2166136261;
hash = (hash * 16777619) ^ Foreground.GetHashCode();
hash = (hash * 16777619) ^ Background.GetHashCode();
hash = (hash * 16777619) ^ Decoration.GetHashCode();
if (Link != null)
{
hash = (hash * 16777619) ^ Link?.GetHashCode() ?? 0;
}
return hash;
}
}
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return Equals(obj as Style);
}
/// <inheritdoc/>
public bool Equals(Style? other)
{
if (other == null)
{
return false;
}
return Foreground.Equals(other.Foreground) &&
Background.Equals(other.Background) &&
Decoration == other.Decoration &&
string.Equals(Link, other.Link, StringComparison.Ordinal);
}
}
}