forked from cubicdaiya/dtl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ses_display_pretty.hpp
153 lines (137 loc) · 5.01 KB
/
ses_display_pretty.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#ifndef DTL_MODERN_EXTRA_SES_DISPLAY_PRETTY_HPP
#define DTL_MODERN_EXTRA_SES_DISPLAY_PRETTY_HPP
#include "dtl_modern/ses.hpp"
namespace dtl_modern::extra
{
/**
* @struct SesDisplayPretty
*
* @brief Wrapper type for displaying SES in pretty format.
*/
template <Diffable E>
struct SesDisplayPretty
{
const Ses<E>& m_ses;
std::string_view m_sep;
// only checks whether it points to the same ses
bool operator==(const SesDisplayPretty& other) const { return &m_ses == &other.m_ses; }
};
/**
* @brief Create a wrapper for displaying SES in pretty format.
*
* @param ses The SES to display.
* @param sep Separator between lhs sequence and rhs sequence.
* @return The wrapper for displaying SES in pretty format.
*/
template <Diffable E>
SesDisplayPretty<E> display_pretty(const Ses<E>& ses, std::string_view sep = "\n")
{
return { ses, sep };
}
}
#include <fmt/core.h>
#include <fmt/color.h>
template <fmt::formattable E>
requires dtl_modern::Diffable<E>
struct fmt::formatter<dtl_modern::extra::SesDisplayPretty<E>>
{
enum class DisplayLine
{
Both,
Left,
Right
};
constexpr auto parse(format_parse_context& ctx)
{
auto pos = ctx.begin();
while (pos != ctx.end() and *pos != '}') {
switch (*pos) {
case 'l': m_display_line = DisplayLine::Left; break;
case 'r': m_display_line = DisplayLine::Right; break;
case 'f': {
m_colorize_common = true;
++pos;
if (*pos != '}') {
throw fmt::format_error{ "Specifier 'f' must be the last specifier" };
}
return pos;
}
default:
throw fmt::format_error{
"Invalid format specifier; expected 'l', 'r', 'f', 'lf', 'rf', or nothing."
};
}
++pos;
}
return pos;
}
auto format(const dtl_modern::extra::SesDisplayPretty<E>& ses_display, auto& fmt) const
{
const auto& [ses, sep] = ses_display;
const auto red = fmt::bg(fmt::color::red);
const auto green = fmt::bg(fmt::color::green);
const auto dark_red = fmt::bg(fmt::color::dark_red);
const auto dark_green = fmt::bg(fmt::color::dark_green);
switch (m_display_line) {
case DisplayLine::Left: {
for (const auto& [elem, info] : ses.get()) {
using Edit = dtl_modern::SesEdit;
switch (info.m_type) {
case Edit::Delete: fmt::format_to(fmt.out(), red, "{}", elem); break;
case Edit::Add: /* do nothing */ break;
case Edit::Common: {
if (m_colorize_common) {
fmt::format_to(fmt.out(), dark_red, "{}", elem);
} else {
fmt::format_to(fmt.out(), "{}", elem);
}
} break;
}
}
} break;
case DisplayLine::Right: {
for (const auto& [elem, info] : ses.get()) {
using Edit = dtl_modern::SesEdit;
switch (info.m_type) {
case Edit::Delete: /* do nothing */ break;
case Edit::Add: fmt::format_to(fmt.out(), green, "{}", elem); break;
case Edit::Common: {
if (m_colorize_common) {
fmt::format_to(fmt.out(), dark_green, "{}", elem);
} else {
fmt::format_to(fmt.out(), "{}", elem);
}
} break;
}
}
} break;
default: {
auto lhs = fmt::memory_buffer{};
auto rhs = fmt::memory_buffer{};
auto lhs_it = std::back_inserter(lhs);
auto rhs_it = std::back_inserter(rhs);
for (const auto& [elem, info] : ses.get()) {
using Edit = dtl_modern::SesEdit;
switch (info.m_type) {
case Edit::Delete: fmt::format_to(lhs_it, red, "{}", elem); break;
case Edit::Add: fmt::format_to(rhs_it, green, "{}", elem); break;
case Edit::Common: {
if (m_colorize_common) {
fmt::format_to(lhs_it, dark_red, "{}", elem);
fmt::format_to(rhs_it, dark_green, "{}", elem);
} else {
fmt::format_to(lhs_it, "{}", elem);
fmt::format_to(rhs_it, "{}", elem);
}
} break;
}
}
fmt::format_to(fmt.out(), "{}{}{}", fmt::to_string(lhs), sep, fmt::to_string(rhs));
} break;
}
return fmt.out();
}
bool m_colorize_common = false;
DisplayLine m_display_line = DisplayLine::Both;
};
#endif /* end of include guard: DTL_MODERN_EXTRA_SES_DISPLAY_PRETTY_HPP */