#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 #include #include #include #include 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(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