led_ctrl/include/toml11/impl/source_location_impl.hpp
2025-06-05 01:03:12 +00:00

216 lines
6.1 KiB
C++

#ifndef TOML11_SOURCE_LOCATION_IMPL_HPP
#define TOML11_SOURCE_LOCATION_IMPL_HPP
#include "../fwd/source_location_fwd.hpp"
#include "../color.hpp"
#include "../utility.hpp"
#include "../version.hpp"
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <cctype>
namespace toml
{
inline namespace TOML11_INLINE_VERSION_NAMESPACE
{
TOML11_INLINE source_location::source_location(const detail::region& r)
: is_ok_(false),
first_line_(1),
first_column_(1),
first_offset_(1),
last_line_(1),
last_column_(1),
last_offset_(1),
length_(0),
file_name_("unknown file")
{
if(r.is_ok())
{
this->is_ok_ = true;
this->file_name_ = r.source_name();
this->first_line_ = r.first_line_number();
this->first_column_ = r.first_column_number();
this->last_line_ = r.last_line_number();
this->last_column_ = r.last_column_number();
this->length_ = r.length();
const auto lines = r.as_lines();
assert( ! lines.empty());
for(const auto& l : lines)
{
this->line_str_.push_back(l.first);
}
this->first_offset_ = lines.at( 0).second + 1; // to 1-origin
this->last_offset_ = lines.at(lines.size()-1).second + 1;
}
}
TOML11_INLINE std::string const& source_location::first_line() const
{
if(this->line_str_.size() == 0)
{
throw std::out_of_range("toml::source_location::first_line: `lines` is empty");
}
return this->line_str_.front();
}
TOML11_INLINE std::string const& source_location::last_line() const
{
if(this->line_str_.size() == 0)
{
throw std::out_of_range("toml::source_location::first_line: `lines` is empty");
}
return this->line_str_.back();
}
namespace detail
{
TOML11_INLINE std::size_t integer_width_base10(std::size_t i) noexcept
{
std::size_t width = 0;
while(i != 0)
{
i /= 10;
width += 1;
}
return width;
}
TOML11_INLINE std::ostringstream&
format_filename(std::ostringstream& oss, const source_location& loc)
{
// --> example.toml
oss << color::bold << color::blue << " --> " << color::reset
<< color::bold << loc.file_name() << '\n' << color::reset;
return oss;
}
TOML11_INLINE std::ostringstream& format_empty_line(std::ostringstream& oss,
const std::size_t lnw)
{
// |
oss << detail::make_string(lnw + 1, ' ')
<< color::bold << color::blue << " |\n" << color::reset;
return oss;
}
TOML11_INLINE std::ostringstream& format_line(std::ostringstream& oss,
const std::size_t lnw, const std::size_t linenum, const std::string& line)
{
// 10 | key = "value"
oss << ' ' << color::bold << color::blue
<< std::setw(static_cast<int>(lnw))
<< std::right << linenum << " | " << color::reset;
for(const char c : line)
{
if(std::isgraph(c) || c == ' ')
{
oss << c;
}
else
{
oss << show_char(c);
}
}
oss << '\n';
return oss;
}
TOML11_INLINE std::ostringstream& format_underline(std::ostringstream& oss,
const std::size_t lnw, const std::size_t col, const std::size_t len,
const std::string& msg)
{
// | ^^^^^^^-- this part
oss << make_string(lnw + 1, ' ')
<< color::bold << color::blue << " | " << color::reset;
// in case col is 0, so we don't create a string with size_t max length
const std::size_t sanitized_col = col == 0 ? 0 : col - 1 /*1-origin*/;
oss << make_string(sanitized_col, ' ')
<< color::bold << color::red
<< make_string(len, '^') << "-- "
<< color::reset << msg << '\n';
return oss;
}
TOML11_INLINE std::string format_location_impl(const std::size_t lnw,
const std::string& prev_fname,
const source_location& loc, const std::string& msg)
{
std::ostringstream oss;
if(loc.file_name() != prev_fname)
{
format_filename(oss, loc);
if( ! loc.lines().empty())
{
format_empty_line(oss, lnw);
}
}
if(loc.lines().size() == 1)
{
// when column points LF, it exceeds the size of the first line.
std::size_t underline_limit = 1;
if(loc.first_line().size() < loc.first_column_offset())
{
underline_limit = 1;
}
else
{
underline_limit = loc.first_line().size() - loc.first_column_offset() + 1;
}
const auto underline_len = (std::min)(underline_limit, loc.length());
format_line(oss, lnw, loc.first_line_number(), loc.first_line());
format_underline(oss, lnw, loc.first_column_offset(), underline_len, msg);
}
else if(loc.lines().size() == 2)
{
const auto first_underline_len =
loc.first_line().size() - loc.first_column_offset() + 1;
format_line(oss, lnw, loc.first_line_number(), loc.first_line());
format_underline(oss, lnw, loc.first_column_offset(),
first_underline_len, "");
format_line(oss, lnw, loc.last_line_number(), loc.last_line());
format_underline(oss, lnw, 1, loc.last_column_offset(), msg);
}
else if(loc.lines().size() > 2)
{
const auto first_underline_len =
loc.first_line().size() - loc.first_column_offset() + 1;
format_line(oss, lnw, loc.first_line_number(), loc.first_line());
format_underline(oss, lnw, loc.first_column_offset(),
first_underline_len, "and");
if(loc.lines().size() == 3)
{
format_line(oss, lnw, loc.first_line_number()+1, loc.lines().at(1));
format_underline(oss, lnw, 1, loc.lines().at(1).size(), "and");
}
else
{
format_line(oss, lnw, loc.first_line_number()+1, " ...");
format_empty_line(oss, lnw);
}
format_line(oss, lnw, loc.last_line_number(), loc.last_line());
format_underline(oss, lnw, 1, loc.last_column_offset(), msg);
}
// if loc is empty, do nothing.
return oss.str();
}
} // namespace detail
} // TOML11_INLINE_VERSION_NAMESPACE
} // toml
#endif // TOML11_SOURCE_LOCATION_IMPL_HPP