/* * Copyright (c) 2020-2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace Line { class Style { public: bool operator==(Style const&) const = default; enum class XtermColor : int { Default = 9, Black = 0, Red, Green, Yellow, Blue, Magenta, Cyan, White, Unchanged, }; struct AnchoredTag { }; struct UnderlineTag { }; struct BoldTag { }; struct ItalicTag { }; struct Color { bool operator==(Color const&) const = default; explicit Color(XtermColor color) : m_xterm_color(color) , m_is_rgb(false) { } Color(u8 r, u8 g, u8 b) : m_rgb_color({ r, g, b }) , m_is_rgb(true) { } bool is_default() const { return !m_is_rgb && m_xterm_color == XtermColor::Unchanged; } XtermColor m_xterm_color { XtermColor::Unchanged }; Vector m_rgb_color; bool m_is_rgb { false }; }; struct Background : public Color { explicit Background(XtermColor color) : Color(color) { } Background(u8 r, u8 g, u8 b) : Color(r, g, b) { } ByteString to_vt_escape() const; }; struct Foreground : public Color { explicit Foreground(XtermColor color) : Color(color) { } Foreground(u8 r, u8 g, u8 b) : Color(r, g, b) { } ByteString to_vt_escape() const; }; struct Hyperlink { bool operator==(Hyperlink const&) const = default; explicit Hyperlink(StringView link) : m_link(link) { m_has_link = true; } Hyperlink() = default; ByteString to_vt_escape(bool starting) const; bool is_empty() const { return !m_has_link; } ByteString m_link; bool m_has_link { false }; }; struct Mask { bool operator==(Mask const& other) const { return other.mode == mode && other.replacement == replacement; } enum class Mode { ReplaceEntireSelection, ReplaceEachCodePointInSelection, }; explicit Mask(StringView replacement, Mode mode = Mode::ReplaceEntireSelection) : replacement(replacement) , replacement_view(this->replacement) , mode(mode) { } ByteString replacement; mutable Utf8View replacement_view; Mode mode; }; static constexpr UnderlineTag Underline {}; static constexpr BoldTag Bold {}; static constexpr ItalicTag Italic {}; static constexpr AnchoredTag Anchored {}; // Prepare for the horror of templates. template Style(T const& style_arg, Rest... rest) : Style(rest...) { set(style_arg); m_is_empty = false; } Style() = default; static Style reset_style() { return { Foreground(XtermColor::Default), Background(XtermColor::Default), Hyperlink(""sv) }; } Style unified_with(Style const& other, bool prefer_other = true) const { Style style = *this; style.unify_with(other, prefer_other); return style; } void unify_with(Style const&, bool prefer_other = false); bool underline() const { return m_underline; } bool bold() const { return m_bold; } bool italic() const { return m_italic; } Background background() const { return m_background; } Foreground foreground() const { return m_foreground; } Hyperlink hyperlink() const { return m_hyperlink; } Optional mask() const { return m_mask; } void unset_mask() const { m_mask = {}; } void set(ItalicTag const&) { m_italic = true; } void set(BoldTag const&) { m_bold = true; } void set(UnderlineTag const&) { m_underline = true; } void set(Background const& bg) { m_background = bg; } void set(Foreground const& fg) { m_foreground = fg; } void set(Hyperlink const& link) { m_hyperlink = link; } void set(AnchoredTag const&) { m_is_anchored = true; } void set(Mask const& mask) { m_mask = mask; } bool is_anchored() const { return m_is_anchored; } bool is_empty() const { return m_is_empty; } ByteString to_byte_string() const; private: bool m_underline { false }; bool m_bold { false }; bool m_italic { false }; Background m_background { XtermColor::Unchanged }; Foreground m_foreground { XtermColor::Unchanged }; Hyperlink m_hyperlink; mutable Optional m_mask; bool m_is_anchored { false }; bool m_is_empty { true }; }; }