refactor: avoid string construct in format_ul

This commit is contained in:
ToruNiina
2020-07-30 16:11:35 +09:00
parent f23c003d2f
commit 4e6ae9a994

View File

@@ -107,17 +107,20 @@ inline std::string format_underline(const std::string& message,
const std::vector<std::string>& helps = {}, const std::vector<std::string>& helps = {},
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
{ {
assert(!loc_com.empty()); std::size_t line_num_width = 0;
for(const auto& lc : loc_com)
const auto line_num_width = static_cast<int>(std::to_string(std::max_element( {
loc_com.begin(), loc_com.end(), std::uint_least32_t line = lc.first.line();
[](std::pair<source_location, std::string> const& lhs, std::size_t digit = 0;
std::pair<source_location, std::string> const& rhs) while(line != 0)
{ {
return std::to_string(lhs.first.line()).size() < line /= 10;
std::to_string(rhs.first.line()).size(); digit += 1;
} }
)->first.line()).size()); line_num_width = (std::max)(line_num_width, digit);
}
// 1 is the minimum width
line_num_width = std::max<std::size_t>(line_num_width, 1);
std::ostringstream retval; std::ostringstream retval;
@@ -142,58 +145,78 @@ inline std::string format_underline(const std::string& message,
<< color::bold << message << color::reset << '\n'; << color::bold << message << color::reset << '\n';
} }
for(auto iter = loc_com.begin(); iter != loc_com.end(); ++iter) const auto format_one_location = [line_num_width]
(std::ostringstream& oss,
const source_location& loc, const std::string& comment) -> void
{
oss << ' ' << color::bold << color::blue
<< std::setw(static_cast<int>(line_num_width))
<< std::right << loc.line() << " | " << color::reset
<< loc.line_str() << '\n';
oss << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " | " << color::reset
<< make_string(loc.column()-1 /*1-origin*/, ' ');
if(loc.region() == 1)
{
// invalid
// ^------
oss << color::bold << color::red << "^---" << color::reset;
}
else
{
// invalid
// ~~~~~~~
const auto underline_len = (std::min)(
static_cast<std::size_t>(loc.region()), loc.line_str().size());
oss << color::bold << color::red
<< make_string(underline_len, '~') << color::reset;
}
oss << ' ';
oss << comment;
return;
};
assert(!loc_com.empty());
// --> example.toml
// |
retval << color::bold << color::blue << " --> " << color::reset
<< loc_com.front().first.file_name() << '\n';
retval << make_string(line_num_width + 1, ' ')
<< color::bold << color::blue << " | " << color::reset << '\n';
// 1 | key value
// | ^--- missing =
format_one_location(retval, loc_com.front().first, loc_com.front().second);
// process the rest of the locations
for(std::size_t i=1; i<loc_com.size(); ++i)
{ {
const auto& prev = loc_com.at(i-1);
const auto& curr = loc_com.at(i);
retval << '\n';
// if the filenames are the same, print "..." // if the filenames are the same, print "..."
if(iter != loc_com.begin() && if(prev.first.file_name() == curr.first.file_name())
std::prev(iter)->first.file_name() == iter->first.file_name())
{ {
retval << color::bold << color::blue << "\n ...\n" << color::reset; retval << color::bold << color::blue << " ...\n" << color::reset;
} }
else // if filename differs, print " --> filename.toml" else // if filename differs, print " --> filename.toml" again
{ {
if(iter != loc_com.begin()) {retval << '\n';}
retval << color::bold << color::blue << " --> " << color::reset retval << color::bold << color::blue << " --> " << color::reset
<< iter->first.file_name() << '\n'; << curr.first.file_name() << '\n';
// add one almost-empty line for readability retval << make_string(line_num_width + 1, ' ')
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ') << color::bold << color::blue << " |\n" << color::reset;
<< color::bold << color::blue << " | " << color::reset << '\n';
} }
const source_location& loc = iter->first;
const std::string& comment = iter->second;
retval << ' ' << color::bold << color::blue << std::setw(line_num_width) format_one_location(retval, curr.first, curr.second);
<< std::right << loc.line() << " | " << color::reset
<< loc.line_str() << '\n';
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
<< color::bold << color::blue << " | " << color::reset
<< make_string(loc.column()-1 /*1-origin*/, ' ');
if(loc.region() == 1)
{
// invalid
// ^------
retval << color::bold << color::red << "^---" << color::reset;
}
else
{
// invalid
// ~~~~~~~
const auto underline_len = (std::min)(
static_cast<std::size_t>(loc.region()), loc.line_str().size());
retval << color::bold << color::red
<< make_string(underline_len, '~') << color::reset;
}
retval << ' ';
retval << comment;
} }
if(!helps.empty()) if(!helps.empty())
{ {
retval << '\n'; retval << '\n';
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' '); retval << make_string(line_num_width + 1, ' ');
retval << color::bold << color::blue << " | " << color::reset; retval << color::bold << color::blue << " | " << color::reset;
for(const auto& help : helps) for(const auto& help : helps)
{ {