Serenity Operating System
1/*
2 * Copyright (c) 2020-2022, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/DeprecatedString.h>
10#include <AK/Types.h>
11#include <AK/Utf8View.h>
12#include <AK/Vector.h>
13
14namespace Line {
15
16class Style {
17public:
18 bool operator==(Style const&) const = default;
19
20 enum class XtermColor : int {
21 Default = 9,
22 Black = 0,
23 Red,
24 Green,
25 Yellow,
26 Blue,
27 Magenta,
28 Cyan,
29 White,
30 Unchanged,
31 };
32
33 struct AnchoredTag {
34 };
35 struct UnderlineTag {
36 };
37 struct BoldTag {
38 };
39 struct ItalicTag {
40 };
41 struct Color {
42 bool operator==(Color const&) const = default;
43
44 explicit Color(XtermColor color)
45 : m_xterm_color(color)
46 , m_is_rgb(false)
47 {
48 }
49 Color(u8 r, u8 g, u8 b)
50 : m_rgb_color({ r, g, b })
51 , m_is_rgb(true)
52 {
53 }
54
55 bool is_default() const
56 {
57 return !m_is_rgb && m_xterm_color == XtermColor::Unchanged;
58 }
59
60 XtermColor m_xterm_color { XtermColor::Unchanged };
61 Vector<int, 3> m_rgb_color;
62 bool m_is_rgb { false };
63 };
64
65 struct Background : public Color {
66 explicit Background(XtermColor color)
67 : Color(color)
68 {
69 }
70 Background(u8 r, u8 g, u8 b)
71 : Color(r, g, b)
72 {
73 }
74 DeprecatedString to_vt_escape() const;
75 };
76
77 struct Foreground : public Color {
78 explicit Foreground(XtermColor color)
79 : Color(color)
80 {
81 }
82 Foreground(u8 r, u8 g, u8 b)
83 : Color(r, g, b)
84 {
85 }
86
87 DeprecatedString to_vt_escape() const;
88 };
89
90 struct Hyperlink {
91 bool operator==(Hyperlink const&) const = default;
92
93 explicit Hyperlink(StringView link)
94 : m_link(link)
95 {
96 m_has_link = true;
97 }
98
99 Hyperlink() = default;
100
101 DeprecatedString to_vt_escape(bool starting) const;
102
103 bool is_empty() const { return !m_has_link; }
104
105 DeprecatedString m_link;
106 bool m_has_link { false };
107 };
108
109 struct Mask {
110 bool operator==(Mask const& other) const
111 {
112 return other.mode == mode && other.replacement == replacement;
113 }
114
115 enum class Mode {
116 ReplaceEntireSelection,
117 ReplaceEachCodePointInSelection,
118 };
119 explicit Mask(StringView replacement, Mode mode = Mode::ReplaceEntireSelection)
120 : replacement(replacement)
121 , replacement_view(this->replacement)
122 , mode(mode)
123 {
124 }
125
126 DeprecatedString replacement;
127 mutable Utf8View replacement_view;
128 Mode mode;
129 };
130
131 static constexpr UnderlineTag Underline {};
132 static constexpr BoldTag Bold {};
133 static constexpr ItalicTag Italic {};
134 static constexpr AnchoredTag Anchored {};
135
136 // Prepare for the horror of templates.
137 template<typename T, typename... Rest>
138 Style(T const& style_arg, Rest... rest)
139 : Style(rest...)
140 {
141 set(style_arg);
142 m_is_empty = false;
143 }
144 Style() = default;
145
146 static Style reset_style()
147 {
148 return { Foreground(XtermColor::Default), Background(XtermColor::Default), Hyperlink(""sv) };
149 }
150
151 Style unified_with(Style const& other, bool prefer_other = true) const
152 {
153 Style style = *this;
154 style.unify_with(other, prefer_other);
155 return style;
156 }
157
158 void unify_with(Style const&, bool prefer_other = false);
159
160 bool underline() const { return m_underline; }
161 bool bold() const { return m_bold; }
162 bool italic() const { return m_italic; }
163 Background background() const { return m_background; }
164 Foreground foreground() const { return m_foreground; }
165 Hyperlink hyperlink() const { return m_hyperlink; }
166 Optional<Mask> mask() const { return m_mask; }
167
168 void unset_mask() const { m_mask = {}; }
169
170 void set(ItalicTag const&) { m_italic = true; }
171 void set(BoldTag const&) { m_bold = true; }
172 void set(UnderlineTag const&) { m_underline = true; }
173 void set(Background const& bg) { m_background = bg; }
174 void set(Foreground const& fg) { m_foreground = fg; }
175 void set(Hyperlink const& link) { m_hyperlink = link; }
176 void set(AnchoredTag const&) { m_is_anchored = true; }
177 void set(Mask const& mask) { m_mask = mask; }
178
179 bool is_anchored() const { return m_is_anchored; }
180 bool is_empty() const { return m_is_empty; }
181
182 DeprecatedString to_deprecated_string() const;
183
184private:
185 bool m_underline { false };
186 bool m_bold { false };
187 bool m_italic { false };
188 Background m_background { XtermColor::Unchanged };
189 Foreground m_foreground { XtermColor::Unchanged };
190 Hyperlink m_hyperlink;
191 mutable Optional<Mask> m_mask;
192
193 bool m_is_anchored { false };
194
195 bool m_is_empty { true };
196};
197}