33 constexpr std::array pairing_color {
34 fmt::color::light_blue,
35 fmt::color::light_green,
36 fmt::color::light_salmon,
37 fmt::color::light_yellow,
38 fmt::color::light_cyan,
39 fmt::color::light_coral
42 constexpr std::size_t pairing_color_size = pairing_color.size();
44 for (
const char& c : line)
48 std::size_t pairing_color_index = 0;
53 pairing_color_index =
static_cast<std::size_t
>(std::abs(line_color_context_counts.
open_parentheses)) % pairing_color_size;
58 pairing_color_index =
static_cast<std::size_t
>(std::abs(line_color_context_counts.
open_parentheses)) % pairing_color_size;
61 pairing_color_index =
static_cast<std::size_t
>(std::abs(line_color_context_counts.
open_square_braces)) % pairing_color_size;
66 pairing_color_index =
static_cast<std::size_t
>(std::abs(line_color_context_counts.
open_square_braces)) % pairing_color_size;
69 pairing_color_index =
static_cast<std::size_t
>(std::abs(line_color_context_counts.
open_curly_braces)) % pairing_color_size;
74 pairing_color_index =
static_cast<std::size_t
>(std::abs(line_color_context_counts.
open_curly_braces)) % pairing_color_size;
80 fmt::print(ss,
"{}", fmt::styled(c, fmt::fg(pairing_color[pairing_color_index])));
83 fmt::print(ss,
"{}", c);
89 const std::string& filename,
90 const std::optional<std::string>& expr,
91 const std::size_t sym_size,
92 const std::size_t target_line,
93 const std::size_t col_start,
94 const std::optional<CodeErrorContext>& maybe_context,
95 const bool whole_line,
98 assert(!(maybe_context && whole_line) &&
"Can not create error context when a context is given AND the whole line has to be underlined");
102 auto show_file_location = [&] {
104 fmt::print(os,
"In file {}:{}\n", filename, target_line + 1);
106 fmt::print(os,
"At {} @ {}:{}\n", expr.value(), target_line + 1, col_start);
109 auto compute_start_end_window = [](
const std::size_t center_of_window,
const std::size_t line_count) {
110 std::size_t start = center_of_window >= 3 ? center_of_window - 3 : 0;
111 std::size_t end = center_of_window + 3 <= line_count ? center_of_window + 3 : line_count;
112 return std::make_pair(start, end);
115 auto print_line = [&os, colorize](
const std::size_t i,
const std::vector<std::string>& lines,
LineColorContextCounts& color_context) {
117 fmt::print(os,
"{: >5} |{}", i + 1, !lines[i].empty() ?
" " :
"");
121 fmt::print(os,
"{}", lines[i]);
122 fmt::print(os,
"\n");
125 const std::string line_no_num =
" |";
127 auto print_context_hint = [&os, &maybe_context, &line_no_num, colorize]()
mutable {
131 fmt::print(os,
"{}", line_no_num);
137 std::max(1_z, maybe_context->col),
140 maybe_context->is_macro_expansion ?
"^ macro expansion started here" :
"^ expression started here",
141 colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
146 if (target_line >= lines.size() || code.empty())
149 show_file_location();
153 auto [first_line, last_line] = compute_start_end_window(target_line, lines.size());
155 std::size_t overflow = (col_start + sym_size < lines[target_line].size()) ? 0 : col_start + sym_size - lines[target_line].size();
157 const bool ctx_same_file = maybe_context && maybe_context->filename == filename;
158 const bool ctx_in_window = ctx_same_file && maybe_context &&
159 maybe_context->line >= first_line &&
160 maybe_context->line < last_line;
162 std::size_t start_line_skipping_at = 0;
163 std::size_t stop_line_skipping_at = first_line;
164 if (ctx_same_file && !ctx_in_window)
167 if (maybe_context->line + 3 < first_line)
168 start_line_skipping_at = maybe_context->line + 3;
170 stop_line_skipping_at = start_line_skipping_at;
174 first_line = maybe_context->line >= 3 ? maybe_context->line - 3 : 0;
176 else if (maybe_context && !ctx_same_file && !maybe_context->filename.empty())
179 fmt::print(os,
"Error originated from file {}:{}\n", maybe_context->filename, maybe_context->line + 1);
182 auto [ctx_first_line, ctx_last_line] = compute_start_end_window(maybe_context->line, ctx_source_lines.size());
185 for (
auto i = ctx_first_line; i < ctx_last_line; ++i)
187 print_line(i, ctx_source_lines, line_color_context_counts);
188 if (i == maybe_context->line)
189 print_context_hint();
192 fmt::print(os,
"\n");
195 show_file_location();
198 for (
auto i = first_line; i < last_line; ++i)
200 if (i >= start_line_skipping_at && i < stop_line_skipping_at)
202 print_line(i, lines, line_color_context_counts);
205 if (maybe_context && i == maybe_context->line && i != target_line)
206 print_context_hint();
210 if (i + 1 == start_line_skipping_at && i + 1 != stop_line_skipping_at)
211 fmt::print(os,
" ... |\n");
214 if (i == target_line || (i > target_line && overflow > 0 && !lines[i].empty()))
216 fmt::print(os,
"{}", line_no_num);
221 const std::size_t curr_col_start = (overflow == 0) ? col_start : 0;
223 const std::size_t col_end = (i == target_line) ? std::min<std::size_t>(col_start + sym_size, lines[target_line].size())
224 : std::min<std::size_t>(overflow, lines[i].size());
226 overflow = (overflow > lines[i].size()) ? overflow - lines[i].size() : 0;
229 if (!maybe_context || maybe_context->line != target_line)
235 std::max(1_z, curr_col_start),
237 fmt::styled(
"^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
238 col_end - curr_col_start);
239 else if (i == target_line)
241 const auto padding_size = std::max(1_z, maybe_context->col);
250 fmt::styled(
"│", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
253 (col_start - maybe_context->col <= 2) ?
"" : fmt::format(
"{: <{}}",
" ", col_start - maybe_context->col - 2),
255 fmt::styled(
"└─ error", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
257 fmt::print(os,
"{}{: <{}}{}\n", line_no_num,
" ", padding_size, fmt::styled(
"│", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
267 maybe_context->is_macro_expansion ?
"└─ macro expansion started here" :
"└─ expression started here",
268 colorize ? fmt::fg(fmt::color::red) : fmt::text_style()));
275 const std::size_t curr_col_start = lines[i].find_first_not_of(
" \t\v") + 1;
285 fmt::styled(
"^", colorize ? fmt::fg(fmt::color::red) : fmt::text_style()),
286 lines[target_line].size() - curr_col_start);