Skip to content

Commit d98e573

Browse files
#72 Complete rework of color formatter, added proper sgr encoding. Color flags parsing problem is fixed
1 parent 67605b2 commit d98e573

File tree

7 files changed

+183
-71
lines changed

7 files changed

+183
-71
lines changed

lwlog/include/details/argument_formatter/argument_buffers_pool_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ namespace lwlog::details
6161
return m_args_buffers[slot_index];
6262
}
6363

64-
template<typename BufferLimits>
64+
template<typename BufferLimits>
6565
const char(&argument_buffers_pool<BufferLimits>::get_args_buffer(std::uint8_t slot_index) const)
6666
[BufferLimits::arg_count][BufferLimits::argument]
6767
{

lwlog/include/details/memory_buffer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include <cstring>
44
#include <cstddef>
55
#include <memory>
6-
#include <string_view>
6+
#include <string>
77
#include <charconv>
88

99
namespace lwlog::details

lwlog/include/details/pattern/color_format_data.h

Lines changed: 0 additions & 43 deletions
This file was deleted.

lwlog/include/details/pattern/pattern.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#pragma once
22

3+
#include <string>
34
#include <memory>
45
#include <vector>
5-
#include <unordered_map>
66
#include <algorithm>
77

88
#include "attribute.h"
99
#include "formatter.h"
1010
#include "alignment_formatter.h"
11+
#include "sgr_encoder.h"
1112
#include "details/record.h"
1213
#include "details/memory_buffer.h"
1314

@@ -35,6 +36,8 @@ namespace lwlog::details
3536
std::vector<std::string_view> parse_short_flags();
3637

3738
private:
39+
sgr_encoder color_encoder;
40+
3841
details::memory_buffer<BufferLimits::pattern> m_pattern_buffer;
3942

4043
char m_cached_pattern_buffer[BufferLimits::pattern];

lwlog/include/details/pattern/pattern_impl.h

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

33
#include "pattern.h"
4-
#include "color_format_data.h"
54
#include "formatters.h"
65

76
namespace lwlog::details
@@ -94,42 +93,68 @@ namespace lwlog::details
9493
template<typename BufferLimits>
9594
void pattern<BufferLimits>::process_color_flags(bool use_color)
9695
{
97-
const char* const reset_seq{ use_color ? "\u001b[0m" : "" };
98-
const std::uint8_t reset_seq_len{ use_color ?
99-
static_cast<std::uint8_t>(4) :
100-
static_cast<std::uint8_t>(0)
101-
};
96+
memory_buffer<10> color_buffer;
97+
98+
const char* const reset_seq{ use_color ? sgr_encoder::reset : "" };
99+
const std::uint8_t reset_seq_len{ use_color ? sgr_encoder::reset_length : static_cast<std::uint8_t>(0) };
102100

103101
std::size_t pos{ 0 };
102+
std::size_t dot_pos{ std::string_view::npos };
103+
std::size_t open_brace_pos{ std::string_view::npos };
104+
std::size_t close_brace_pos{ std::string_view::npos };
105+
106+
bool is_flag_valid{ true };
107+
104108
while (pos < m_pattern_buffer.size())
105109
{
106110
if (m_pattern_buffer[pos] == '.')
107111
{
108-
const std::size_t color_seq_end_pos{ m_pattern_buffer.data().find("(", pos) };
109-
const std::string_view color_flag{ m_pattern_buffer.c_str() + pos, color_seq_end_pos - pos + 1 };
110-
111-
if (const auto it = color_data.find(color_flag); it != color_data.end())
112-
{
113-
const char* const color_seq{ use_color ? it->second.data() : "" };
114-
const std::size_t color_seq_len{ use_color ? it->second.size() : 0 };
115-
116-
m_pattern_buffer.replace(pos, color_seq_end_pos - pos + 1, color_seq, color_seq_len);
117-
pos += color_seq_len;
118-
}
119-
else
120-
{
121-
++pos;
122-
}
112+
dot_pos = pos;
113+
is_flag_valid = true;
114+
}
115+
else if (m_pattern_buffer[pos] == '(')
116+
{
117+
open_brace_pos = pos;
123118
}
124119
else if (m_pattern_buffer[pos] == ')')
125120
{
126-
m_pattern_buffer.replace(pos, 1, reset_seq, reset_seq_len);
127-
pos += reset_seq_len;
121+
close_brace_pos = pos;
128122
}
129-
else
123+
else if (m_pattern_buffer[pos] == ' ' && dot_pos != std::string_view::npos
124+
&& (pos > dot_pos) && (pos < open_brace_pos))
130125
{
131-
++pos;
126+
is_flag_valid = false;
132127
}
128+
129+
if (dot_pos != std::string_view::npos && open_brace_pos != std::string_view::npos
130+
&& close_brace_pos != std::string_view::npos)
131+
{
132+
if ((dot_pos < open_brace_pos && open_brace_pos < close_brace_pos) && is_flag_valid == true)
133+
{
134+
const std::size_t color_flag_len{ open_brace_pos - dot_pos + 1 };
135+
const std::size_t color_name_len{ open_brace_pos - dot_pos - 1 };
136+
const std::string_view color_name{ &m_pattern_buffer[dot_pos + 1], color_name_len };
137+
138+
color_encoder.encode(color_name, color_buffer);
139+
140+
const char* const color_seq{ use_color ? color_buffer.c_str() : "" };
141+
const std::size_t color_seq_len{ use_color ? color_buffer.size() : 0 };
142+
143+
m_pattern_buffer.replace(dot_pos, color_flag_len, color_seq, color_seq_len);
144+
145+
const std::size_t recalculate_close_brace_pos{ close_brace_pos - color_flag_len + color_seq_len };
146+
m_pattern_buffer.replace(recalculate_close_brace_pos, 1, reset_seq, reset_seq_len);
147+
148+
pos = recalculate_close_brace_pos + reset_seq_len;
149+
150+
is_flag_valid = true;
151+
dot_pos = std::string_view::npos;
152+
open_brace_pos = std::string_view::npos;
153+
close_brace_pos = std::string_view::npos;
154+
}
155+
}
156+
157+
++pos;
133158
}
134159
}
135160

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include "sgr_encoder.h"
2+
#include <iostream>
3+
4+
namespace lwlog::details
5+
{
6+
void sgr_encoder::encode(std::string_view token, memory_buffer<10>& out)
7+
{
8+
std::string_view name{ token };
9+
10+
bool is_background{ false };
11+
bool is_dark{ false };
12+
13+
constexpr auto starts_with = [](std::string_view str, std::string_view prefix) {
14+
return str.compare(0, prefix.size(), prefix) == 0;
15+
};
16+
17+
if (starts_with(name, "bg_")) { is_background = true; name.remove_prefix(3); }
18+
if (starts_with(name, "dark_")) { is_dark = true; name.remove_prefix(5); }
19+
20+
const sgr_color_spec* spec{ sgr_encoder::find_color_spec(name) };
21+
if (!spec)
22+
{
23+
out.append(token);
24+
return;
25+
}
26+
27+
const std::uint8_t code{ sgr_encoder::resolve_color(*spec, is_background, is_dark) };
28+
29+
char code_digits[3]{};
30+
std::uint8_t code_digits_count{};
31+
if (code >= 100)
32+
{
33+
code_digits[0] = '1';
34+
code_digits[1] = '0' + char((code / 10) % 10);
35+
code_digits[2] = '0' + char(code % 10);
36+
code_digits_count = 3;
37+
}
38+
else
39+
{
40+
code_digits[0] = '0' + char(code / 10);
41+
code_digits[1] = '0' + char(code % 10);
42+
code_digits_count = 2;
43+
}
44+
45+
out.append("\x1b[");
46+
out.append(code_digits, code_digits_count);
47+
out.append('m');
48+
}
49+
50+
const sgr_color_spec* sgr_encoder::find_color_spec(std::string_view color)
51+
{
52+
for (const auto& spec : sgr_colors)
53+
{
54+
if (spec.base_name == color)
55+
{
56+
return &spec;
57+
}
58+
}
59+
60+
return nullptr;
61+
}
62+
63+
const std::uint8_t sgr_encoder::resolve_color(const sgr_color_spec& spec, bool is_background, bool is_dark)
64+
{
65+
const std::uint8_t channel_offset{ static_cast<std::uint8_t>(is_background ?
66+
color_channel_offset::background : color_channel_offset::foreground) };
67+
68+
if (spec.base_name == "grey")
69+
{
70+
const std::uint8_t grey_offset{ static_cast<std::uint8_t>(is_dark ?
71+
sgr_encoder::intensity_offset - 7 : 0) };
72+
return spec.fg_base_code + channel_offset + grey_offset;
73+
}
74+
75+
if (spec.base_name == "black")
76+
{
77+
return spec.fg_base_code + channel_offset;
78+
}
79+
80+
const std::uint8_t color_intensity_offset{ static_cast<std::uint8_t>(
81+
!is_dark ? sgr_encoder::intensity_offset : 0)
82+
};
83+
return spec.fg_base_code + channel_offset + color_intensity_offset;
84+
}
85+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include "details/memory_buffer.h"
4+
5+
namespace lwlog::details
6+
{
7+
struct sgr_color_spec
8+
{
9+
std::string_view base_name;
10+
std::uint8_t fg_base_code;
11+
};
12+
13+
constexpr inline sgr_color_spec sgr_colors[] =
14+
{
15+
{ "black", 30 },
16+
{ "white", 37 },
17+
{ "grey", 37 },
18+
{ "red", 31 },
19+
{ "green", 32 },
20+
{ "yellow", 33 },
21+
{ "blue", 34 },
22+
{ "magenta", 35 },
23+
{ "cyan", 36 }
24+
};
25+
26+
class sgr_encoder
27+
{
28+
enum class color_channel_offset { foreground = 0, background = 10 };
29+
static constexpr std::uint8_t intensity_offset{ 60 };
30+
31+
public:
32+
static constexpr const char* const reset{ "\x1b[0m" };
33+
static constexpr std::uint8_t reset_length{ 4 };
34+
35+
public:
36+
static void encode(std::string_view token, memory_buffer<10>& out);
37+
38+
private:
39+
static const sgr_color_spec* find_color_spec(std::string_view color);
40+
static const std::uint8_t resolve_color(const sgr_color_spec&, bool is_background, bool is_dark);
41+
};
42+
}

0 commit comments

Comments
 (0)