comparison dep/toml11/toml/source_location.hpp @ 318:3b355fa948c7

config: use TOML instead of INI unfortunately, INI is not enough, and causes some paths including semicolons to break with our current storage of the library folders. so, I decided to switch to TOML which does support real arrays...
author Paper <paper@paper.us.eu.org>
date Wed, 12 Jun 2024 05:25:41 -0400
parents
children
comparison
equal deleted inserted replaced
317:b1f4d1867ab1 318:3b355fa948c7
1 // Copyright Toru Niina 2019.
2 // Distributed under the MIT License.
3 #ifndef TOML11_SOURCE_LOCATION_HPP
4 #define TOML11_SOURCE_LOCATION_HPP
5 #include <cstdint>
6 #include <sstream>
7
8 #include "region.hpp"
9
10 namespace toml
11 {
12
13 // A struct to contain location in a toml file.
14 // The interface imitates std::experimental::source_location,
15 // but not completely the same.
16 //
17 // It would be constructed by toml::value. It can be used to generate
18 // user-defined error messages.
19 //
20 // - std::uint_least32_t line() const noexcept
21 // - returns the line number where the region is on.
22 // - std::uint_least32_t column() const noexcept
23 // - returns the column number where the region starts.
24 // - std::uint_least32_t region() const noexcept
25 // - returns the size of the region.
26 //
27 // +-- line() +-- region of interest (region() == 9)
28 // v .---+---.
29 // 12 | value = "foo bar"
30 // ^
31 // +-- column()
32 //
33 // - std::string const& file_name() const noexcept;
34 // - name of the file.
35 // - std::string const& line_str() const noexcept;
36 // - the whole line that contains the region of interest.
37 //
38 struct source_location
39 {
40 public:
41
42 source_location()
43 : line_num_(1), column_num_(1), region_size_(1),
44 file_name_("unknown file"), line_str_("")
45 {}
46
47 explicit source_location(const detail::region_base* reg)
48 : line_num_(1), column_num_(1), region_size_(1),
49 file_name_("unknown file"), line_str_("")
50 {
51 if(reg)
52 {
53 if(reg->line_num() != detail::region_base().line_num())
54 {
55 line_num_ = static_cast<std::uint_least32_t>(
56 std::stoul(reg->line_num()));
57 }
58 column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
59 region_size_ = static_cast<std::uint_least32_t>(reg->size());
60 file_name_ = reg->name();
61 line_str_ = reg->line();
62 }
63 }
64
65 explicit source_location(const detail::region& reg)
66 : line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
67 column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
68 region_size_(static_cast<std::uint_least32_t>(reg.size())),
69 file_name_(reg.name()),
70 line_str_ (reg.line())
71 {}
72 explicit source_location(const detail::location& loc)
73 : line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
74 column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
75 region_size_(static_cast<std::uint_least32_t>(loc.size())),
76 file_name_(loc.name()),
77 line_str_ (loc.line())
78 {}
79
80 ~source_location() = default;
81 source_location(source_location const&) = default;
82 source_location(source_location &&) = default;
83 source_location& operator=(source_location const&) = default;
84 source_location& operator=(source_location &&) = default;
85
86 std::uint_least32_t line() const noexcept {return line_num_;}
87 std::uint_least32_t column() const noexcept {return column_num_;}
88 std::uint_least32_t region() const noexcept {return region_size_;}
89
90 std::string const& file_name() const noexcept {return file_name_;}
91 std::string const& line_str() const noexcept {return line_str_;}
92
93 private:
94
95 std::uint_least32_t line_num_;
96 std::uint_least32_t column_num_;
97 std::uint_least32_t region_size_;
98 std::string file_name_;
99 std::string line_str_;
100 };
101
102 namespace detail
103 {
104
105 // internal error message generation.
106 inline std::string format_underline(const std::string& message,
107 const std::vector<std::pair<source_location, std::string>>& loc_com,
108 const std::vector<std::string>& helps = {},
109 const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
110 {
111 std::size_t line_num_width = 0;
112 for(const auto& lc : loc_com)
113 {
114 std::uint_least32_t line = lc.first.line();
115 std::size_t digit = 0;
116 while(line != 0)
117 {
118 line /= 10;
119 digit += 1;
120 }
121 line_num_width = (std::max)(line_num_width, digit);
122 }
123 // 1 is the minimum width
124 line_num_width = std::max<std::size_t>(line_num_width, 1);
125
126 std::ostringstream retval;
127
128 if(color::should_color() || colorize)
129 {
130 retval << color::colorize; // turn on ANSI color
131 }
132
133 // XXX
134 // Here, before `colorize` support, it does not output `[error]` prefix
135 // automatically. So some user may output it manually and this change may
136 // duplicate the prefix. To avoid it, check the first 7 characters and
137 // if it is "[error]", it removes that part from the message shown.
138 if(message.size() > 7 && message.substr(0, 7) == "[error]")
139 {
140 retval
141 #ifndef TOML11_NO_ERROR_PREFIX
142 << color::bold << color::red << "[error]" << color::reset
143 #endif
144 << color::bold << message.substr(7) << color::reset << '\n';
145 }
146 else
147 {
148 retval
149 #ifndef TOML11_NO_ERROR_PREFIX
150 << color::bold << color::red << "[error] " << color::reset
151 #endif
152 << color::bold << message << color::reset << '\n';
153 }
154
155 const auto format_one_location = [line_num_width]
156 (std::ostringstream& oss,
157 const source_location& loc, const std::string& comment) -> void
158 {
159 oss << ' ' << color::bold << color::blue
160 << std::setw(static_cast<int>(line_num_width))
161 << std::right << loc.line() << " | " << color::reset
162 << loc.line_str() << '\n';
163
164 oss << make_string(line_num_width + 1, ' ')
165 << color::bold << color::blue << " | " << color::reset
166 << make_string(loc.column()-1 /*1-origin*/, ' ');
167
168 if(loc.region() == 1)
169 {
170 // invalid
171 // ^------
172 oss << color::bold << color::red << "^---" << color::reset;
173 }
174 else
175 {
176 // invalid
177 // ~~~~~~~
178 const auto underline_len = (std::min)(
179 static_cast<std::size_t>(loc.region()), loc.line_str().size());
180 oss << color::bold << color::red
181 << make_string(underline_len, '~') << color::reset;
182 }
183 oss << ' ';
184 oss << comment;
185 return;
186 };
187
188 assert(!loc_com.empty());
189
190 // --> example.toml
191 // |
192 retval << color::bold << color::blue << " --> " << color::reset
193 << loc_com.front().first.file_name() << '\n';
194 retval << make_string(line_num_width + 1, ' ')
195 << color::bold << color::blue << " |\n" << color::reset;
196 // 1 | key value
197 // | ^--- missing =
198 format_one_location(retval, loc_com.front().first, loc_com.front().second);
199
200 // process the rest of the locations
201 for(std::size_t i=1; i<loc_com.size(); ++i)
202 {
203 const auto& prev = loc_com.at(i-1);
204 const auto& curr = loc_com.at(i);
205
206 retval << '\n';
207 // if the filenames are the same, print "..."
208 if(prev.first.file_name() == curr.first.file_name())
209 {
210 retval << color::bold << color::blue << " ...\n" << color::reset;
211 }
212 else // if filename differs, print " --> filename.toml" again
213 {
214 retval << color::bold << color::blue << " --> " << color::reset
215 << curr.first.file_name() << '\n';
216 retval << make_string(line_num_width + 1, ' ')
217 << color::bold << color::blue << " |\n" << color::reset;
218 }
219
220 format_one_location(retval, curr.first, curr.second);
221 }
222
223 if(!helps.empty())
224 {
225 retval << '\n';
226 retval << make_string(line_num_width + 1, ' ');
227 retval << color::bold << color::blue << " |" << color::reset;
228 for(const auto& help : helps)
229 {
230 retval << color::bold << "\nHint: " << color::reset;
231 retval << help;
232 }
233 }
234 return retval.str();
235 }
236
237 } // detail
238 } // toml
239 #endif// TOML11_SOURCE_LOCATION_HPP