ArkScript
A small, lisp-inspired, functional scripting language
PrettyPrinting.cpp
Go to the documentation of this file.
2
3#include <Ark/Constants.hpp>
4#include <Ark/Utils/Files.hpp>
5#include <Ark/Utils/Utils.hpp>
6
7#include <array>
8#include <cassert>
9
10#include <fmt/color.h>
11#include <fmt/ostream.h>
12
13namespace Ark::Diagnostics
14{
15 [[nodiscard]] bool isPairableChar(const char c)
16 {
17 return c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}';
18 }
19
20 void colorizeLine(const std::string& line, LineColorContextCounts& ctx, std::ostream& os)
21 {
22 // clang-format off
23 constexpr std::array pairing_color {
24 fmt::color::light_blue,
25 fmt::color::light_green,
26 fmt::color::light_salmon,
27 fmt::color::light_yellow,
28 fmt::color::light_cyan,
29 fmt::color::light_coral
30 };
31 // clang-format on
32 constexpr std::size_t pairing_color_size = pairing_color.size();
33
34 for (const char c : line)
35 {
36 if (isPairableChar(c))
37 {
38 int idx = 0;
39
40 switch (c)
41 {
42 case '(':
43 idx = ctx.open_parentheses;
44 ctx.open_parentheses++;
45 break;
46 case ')':
47 ctx.open_parentheses--;
48 idx = ctx.open_parentheses;
49 break;
50 case '[':
51 idx = ctx.open_square_braces;
53 break;
54 case ']':
56 idx = ctx.open_square_braces;
57 break;
58 case '{':
59 idx = ctx.open_curly_braces;
61 break;
62 case '}':
64 idx = ctx.open_curly_braces;
65 break;
66 default:
67 break;
68 }
69
70 const std::size_t pairing_color_index = static_cast<std::size_t>(std::abs(idx)) % pairing_color_size;
71 fmt::print(os, "{}", fmt::styled(c, fmt::fg(pairing_color[pairing_color_index])));
72 }
73 else
74 fmt::print(os, "{}", c);
75 }
76 }
77
79 const std::string& filename, const std::size_t target_line,
80 const std::optional<std::size_t> end_target_line, const bool colorize) :
81 m_should_colorize(colorize)
82 {
83 const std::string code = filename == ARK_NO_NAME_FILE ? "" : Utils::readFile(filename);
84 m_source = Utils::splitString(code, '\n');
85
86 m_window = Window(target_line, end_target_line.value_or(target_line), m_source.size());
88 }
89
90 std::string Printer::sliceCode(const internal::FilePos start, const std::optional<internal::FilePos>& end) const
91 {
92 std::string code;
93 if (!end)
94 {
95 code = m_source[start.line];
97 }
98 else
99 {
100 if (start.line == end->line)
101 code = m_source[start.line].substr(start.column, end->column);
102 else
103 {
104 code = m_source[start.line].substr(start.column);
105
106 if (end->line - start.line > 1)
107 {
108 for (std::size_t i = start.line + 1; i <= end->line - 1; ++i)
109 {
110 code += "\n";
111 code += m_source[i];
112 }
113 }
114 code += "\n" + m_source[end->line].substr(0, end->column);
115 }
116 }
117
118 return code;
119 }
120
121 void Printer::extendWindow(const std::size_t line_to_include)
122 {
123 // showing the context will require an ellipsis, to avoid showing too many lines in the error message
124 if (line_to_include + 3 < m_window.start)
125 m_window.skip_start_at = line_to_include + 3;
127
128 assert(line_to_include <= m_window.start && "line_to_include has to be before the start of our base context, source of errors are always before our errors");
129 // due to how context works, if it points to the same file,
130 // we are guaranteed it will be before our error
131 m_window.start = line_to_include >= 3 ? line_to_include - 3 : 0;
133 }
134
135 void Printer::printLine(std::ostream& os)
136 {
137 if (!hasContent())
138 return;
139
140 if (m_window.hasSkip() &&
143 {
144 // do not print the current line, we want to skip 1 or more lines
146 return;
147 }
148
149 // show current line with its number
150 fmt::print(os, "{: >5} |{}", m_current_line + 1, !m_source[m_current_line].empty() ? " " : "");
153 else
154 fmt::print(os, "{}", m_source[m_current_line]);
155 fmt::print(os, "\n");
156
158
159 // if skip_start_at is equal to the next line to print, and we have to skip,
160 // display an ellipsis
163 fmt::print(os, " ... |\n");
164 }
165
167 {
169 }
170
172 {
173 return m_current_line < m_window.end && !m_source.empty() && m_window.target < m_window.end;
174 }
175
176 bool Printer::coversLine(const std::size_t line_number) const
177 {
178 return m_window.start <= line_number && line_number < m_window.end;
179 }
180
181}
Lots of utilities about string, filesystem and more.
Constants used by ArkScript.
#define ARK_NO_NAME_FILE
Definition Constants.hpp:27
Lots of utilities about the filesystem.
Pretty printing utilities for diagnostics.
std::string sliceCode(internal::FilePos start, const std::optional< internal::FilePos > &end) const
Slice the source code to get code between two cursors.
void extendWindow(std::size_t line_to_include)
Extend the window of lines to show, to include a given line. Useful to display the origin of an error...
Printer(const std::string &filename, std::size_t target_line, std::optional< std::size_t > end_target_line, bool colorize)
Create a new Printer object.
bool isTargetLine() const
Check if we printed the target line.
std::vector< std::string > m_source
LineColorContextCounts m_color_ctx
bool coversLine(std::size_t line_number) const
bool hasContent() const
Check if there are lines to print.
void printLine(std::ostream &os)
Print the current line and advance by one.
bool isPairableChar(const char c)
void colorizeLine(const std::string &line, LineColorContextCounts &ctx, std::ostream &os)
std::string readFile(const std::string &name)
Helper to read a file.
Definition Files.hpp:47
std::string & ltrim(std::string &s)
Remove spaces at the beginning of a string, in place.
Definition Utils.hpp:52
std::vector< std::string > splitString(const std::string &source, const char sep)
Cut a string into pieces, given a character separator.
Definition Utils.hpp:31
std::string & rtrim(std::string &s)
Remove spaces at the end of a string, in place.
Definition Utils.hpp:67
std::optional< std::size_t > skip_start_at
std::optional< std::size_t > resume_at
std::size_t end
Last line of the context, not displayed.
std::size_t start
First line number to display.
std::size_t column
0-indexed column number
Definition Position.hpp:23
std::size_t line
0-indexed line number
Definition Position.hpp:22