From c2d0351e6929a7cc6eeae4ff4c4a0cd59890d050 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 17:24:51 +0900 Subject: [PATCH 01/17] feat: add (ANSI) terminal colorize operators --- toml/color.hpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 toml/color.hpp diff --git a/toml/color.hpp b/toml/color.hpp new file mode 100644 index 0000000..514632b --- /dev/null +++ b/toml/color.hpp @@ -0,0 +1,78 @@ +#ifndef TOML11_COLOR_HPP +#define TOML11_COLOR_HPP +#include +#include + +namespace toml +{ + +// put ANSI escape sequence to ostream +namespace color_ansi +{ +namespace detail +{ +inline int colorize_index() +{ + static const int index = std::ios_base::xalloc(); + return index; +} +} // detail + +inline std::ostream& colorize(std::ostream& os) +{ + // by default, it is zero. + os.iword(detail::colorize_index()) = 1; + return os; +} +inline std::ostream& nocolorize(std::ostream& os) +{ + os.iword(detail::colorize_index()) = 0; + return os; +} +inline std::ostream& reset (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;} +inline std::ostream& bold (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;} +inline std::ostream& grey (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;} +inline std::ostream& red (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;} +inline std::ostream& green (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;} +inline std::ostream& yellow (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;} +inline std::ostream& blue (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;} +inline std::ostream& magenta(std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;} +inline std::ostream& cyan (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;} +inline std::ostream& white (std::ostream& os) +{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;} +} // color_ansi + +// do nothing. +namespace nocolor +{ +inline std::ostream& colorize (std::ostream& os) noexcept {return os;} +inline std::ostream& nocolorize(std::ostream& os) noexcept {return os;} +inline std::ostream& reset (std::ostream& os) noexcept {return os;} +inline std::ostream& bold (std::ostream& os) noexcept {return os;} +inline std::ostream& grey (std::ostream& os) noexcept {return os;} +inline std::ostream& red (std::ostream& os) noexcept {return os;} +inline std::ostream& green (std::ostream& os) noexcept {return os;} +inline std::ostream& yellow (std::ostream& os) noexcept {return os;} +inline std::ostream& blue (std::ostream& os) noexcept {return os;} +inline std::ostream& magenta (std::ostream& os) noexcept {return os;} +inline std::ostream& cyan (std::ostream& os) noexcept {return os;} +inline std::ostream& white (std::ostream& os) noexcept {return os;} +} // nocolor + +#ifdef TOML11_COLORIZE_ERROR_MESSAGE +namespace color = color_ansi; +#else +namespace color = nocolor; +#endif + +} // toml +#endif// TOML11_COLOR_HPP From 87bebbc37d00e20ee2e091204cae00d06d7fee4e Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 17:25:17 +0900 Subject: [PATCH 02/17] feat: put color to the internal error messages --- toml/region.hpp | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index de6d04b..73fc076 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -9,6 +9,7 @@ #include #include #include +#include "color.hpp" namespace toml { @@ -432,7 +433,13 @@ inline std::string format_underline(const std::string& message, )->first->line_num().size()); std::ostringstream retval; - retval << message << '\n'; + +#ifdef TOML11_COLORIZE_ERROR_MESSAGE + retval << color::colorize; // turn on ANSI color +#endif + + retval << color::bold << color::red << "[error] " << color::reset + << color::bold << message << color::reset << '\n'; for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter) { @@ -440,34 +447,41 @@ inline std::string format_underline(const std::string& message, if(iter != reg_com.begin() && std::prev(iter)->first->name() == iter->first->name()) { - retval << "\n ...\n"; + retval << color::bold << color::blue << "\n ...\n" << color::reset; } else // if filename differs, print " --> filename.toml" { if(iter != reg_com.begin()) {retval << '\n';} - retval << " --> " << iter->first->name() << '\n'; + retval << color::bold << color::blue << " --> " << color::reset + << iter->first->name() << '\n'; + // add one almost-empty line for readability + retval << make_string(static_cast(line_num_width + 1), ' ') + << color::bold << color::blue << " | " << color::reset << '\n'; } const region_base* const reg = iter->first; const std::string& comment = iter->second; - retval << ' ' << std::setw(line_num_width) << reg->line_num(); - retval << " | " << reg->line() << '\n'; - retval << make_string(static_cast(line_num_width + 1), ' '); - retval << " | " << make_string(reg->before(), ' '); + retval << ' ' << std::setw(line_num_width) << color::bold << color::blue + << reg->line_num() << " | " << color::reset << reg->line() << '\n'; + + retval << make_string(static_cast(line_num_width + 1), ' ') + << color::bold << color::blue << " | " << color::reset + << make_string(reg->before(), ' '); if(reg->size() == 1) { // invalid // ^------ - retval << '^'; - retval << make_string(reg->after(), '-'); + retval << color::bold << color::red + << '^' << make_string(reg->after(), '-') << color::reset; } else { // invalid // ~~~~~~~ const auto underline_len = std::min(reg->size(), reg->line().size()); - retval << make_string(underline_len, '~'); + retval << color::bold << color::red + << make_string(underline_len, '~') << color::reset; } retval << ' '; retval << comment; @@ -477,10 +491,10 @@ inline std::string format_underline(const std::string& message, { retval << '\n'; retval << make_string(static_cast(line_num_width + 1), ' '); - retval << " | "; + retval << color::bold << color::blue << " | " << color::reset; for(const auto help : helps) { - retval << "\nHint: "; + retval << color::bold << "\nHint: " << color::reset; retval << help; } } From af116991b6e77435cf050b424776fc2de248946f Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 17:35:23 +0900 Subject: [PATCH 03/17] fix: remove overlapping [error] sign --- toml/get.hpp | 20 +++--- toml/parser.hpp | 162 ++++++++++++++++++++++++------------------------ toml/value.hpp | 2 +- 3 files changed, 92 insertions(+), 92 deletions(-) diff --git a/toml/get.hpp b/toml/get.hpp index 2023425..ce2ea54 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -186,7 +186,7 @@ get(const basic_value& v) } default: { - throw type_error(detail::format_underline("[error] toml::value " + throw type_error(detail::format_underline("toml::value: " "bad_cast to std::chrono::system_clock::time_point", { {std::addressof(detail::get_region(v)), concat_to_string("the actual type is ", v.type())} @@ -301,7 +301,7 @@ get(const basic_value& v) if(ar.size() != container.size()) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[erorr] toml::get specified container size is ", container.size(), + "toml::get: specified container size is ", container.size(), " but there are ", ar.size(), " elements in toml array."), { {std::addressof(detail::get_region(v)), "here"} })); @@ -326,7 +326,7 @@ get(const basic_value& v) if(ar.size() != 2) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[erorr] toml::get specified std::pair but there are ", ar.size(), + "toml::get: specified std::pair but there are ", ar.size(), " elements in toml array."), { {std::addressof(detail::get_region(v)), "here"} })); @@ -357,7 +357,7 @@ get(const basic_value& v) if(ar.size() != std::tuple_size::value) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] toml::get specified std::tuple with ", + "toml::get: specified std::tuple with ", std::tuple_size::value, " elements, but there are ", ar.size(), " elements in toml array."), { {std::addressof(detail::get_region(v)), "here"} @@ -430,7 +430,7 @@ basic_value const& find(const basic_value& v, const key& ky) if(tab.count(ky) == 0) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] key \"", ky, "\" not found"), { + "key \"", ky, "\" not found"), { {std::addressof(detail::get_region(v)), "in this table"} })); } @@ -444,7 +444,7 @@ basic_value& find(basic_value& v, const key& ky) if(tab.count(ky) == 0) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] key \"", ky, "\" not found"), { + "key \"", ky, "\" not found"), { {std::addressof(detail::get_region(v)), "in this table"} })); } @@ -458,7 +458,7 @@ basic_value find(basic_value&& v, const key& ky) if(tab.count(ky) == 0) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] key \"", ky, "\" not found"), { + "key \"", ky, "\" not found"), { {std::addressof(detail::get_region(v)), "in this table"} })); } @@ -477,7 +477,7 @@ find(const basic_value& v, const key& ky) if(tab.count(ky) == 0) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] key \"", ky, "\" not found"), { + "key \"", ky, "\" not found"), { {std::addressof(detail::get_region(v)), "in this table"} })); } @@ -493,7 +493,7 @@ find(basic_value& v, const key& ky) if(tab.count(ky) == 0) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] key \"", ky, "\" not found"), { + "key \"", ky, "\" not found"), { {std::addressof(detail::get_region(v)), "in this table"} })); } @@ -509,7 +509,7 @@ find(basic_value&& v, const key& ky) if(tab.count(ky) == 0) { throw std::out_of_range(detail::format_underline(concat_to_string( - "[error] key \"", ky, "\" not found"), { + "key \"", ky, "\" not found"), { {std::addressof(detail::get_region(v)), "in this table"} })); } diff --git a/toml/parser.hpp b/toml/parser.hpp index 0efccf0..be92143 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -30,13 +30,13 @@ parse_boolean(location& loc) else // internal error. { throw internal_error(format_underline( - "[error] toml::parse_boolean: internal error", + "toml::parse_boolean: internal error", {{std::addressof(reg), "invalid token"}}), source_location(std::addressof(reg))); } } loc.reset(first); //rollback - return err(format_underline("[error] toml::parse_boolean: ", + return err(format_underline("toml::parse_boolean: ", {{std::addressof(loc), "the next token is not a boolean"}})); } @@ -58,7 +58,7 @@ parse_binary_integer(location& loc) else // internal error. { throw internal_error(format_underline( - "[error] toml::parse_integer: internal error", + "toml::parse_integer: internal error", {{std::addressof(token.unwrap()), "invalid token"}}), source_location(std::addressof(loc))); } @@ -66,7 +66,7 @@ parse_binary_integer(location& loc) return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); - return err(format_underline("[error] toml::parse_binary_integer:", + return err(format_underline("toml::parse_binary_integer:", {{std::addressof(loc), "the next token is not an integer"}})); } @@ -87,7 +87,7 @@ parse_octal_integer(location& loc) return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); - return err(format_underline("[error] toml::parse_octal_integer:", + return err(format_underline("toml::parse_octal_integer:", {{std::addressof(loc), "the next token is not an integer"}})); } @@ -108,7 +108,7 @@ parse_hexadecimal_integer(location& loc) return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); - return err(format_underline("[error] toml::parse_hexadecimal_integer", + return err(format_underline("toml::parse_hexadecimal_integer", {{std::addressof(loc), "the next token is not an integer"}})); } @@ -131,13 +131,13 @@ parse_integer(location& loc) if(std::isdigit(*second)) { - return err(format_underline("[error] toml::parse_integer: " + return err(format_underline("toml::parse_integer: " "leading zero in an Integer is not allowed.", {{std::addressof(loc), "leading zero"}})); } else if(std::isalpha(*second)) { - return err(format_underline("[error] toml::parse_integer: " + return err(format_underline("toml::parse_integer: " "unknown integer prefix appeared.", {{std::addressof(loc), "none of 0x, 0o, 0b"}})); } @@ -154,7 +154,7 @@ parse_integer(location& loc) return ok(std::make_pair(retval, token.unwrap())); } loc.reset(first); - return err(format_underline("[error] toml::parse_integer: ", + return err(format_underline("toml::parse_integer: ", {{std::addressof(loc), "the next token is not an integer"}})); } @@ -243,7 +243,7 @@ parse_floating(location& loc) return ok(std::make_pair(v, token.unwrap())); } loc.reset(first); - return err(format_underline("[error] toml::parse_floating: ", + return err(format_underline("toml::parse_floating: ", {{std::addressof(loc), "the next token is not a float"}})); } @@ -276,7 +276,7 @@ std::string read_utf8_codepoint(const region& reg, { if(0xD800 <= codepoint && codepoint <= 0xDFFF) { - throw syntax_error(format_underline("[error] " + throw syntax_error(format_underline( "toml::read_utf8_codepoint: codepoints in the range " "[0xD800, 0xDFFF] are not valid UTF-8.", {{ std::addressof(loc), "not a valid UTF-8 codepoint" @@ -298,7 +298,7 @@ std::string read_utf8_codepoint(const region& reg, } else // out of UTF-8 region { - throw syntax_error(format_underline("[error] toml::read_utf8_codepoint:" + throw syntax_error(format_underline("toml::read_utf8_codepoint:" " input codepoint is too large.", {{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}), source_location(std::addressof(loc))); @@ -333,7 +333,7 @@ result parse_escape_sequence(location& loc) } else { - return err(format_underline("[error] parse_escape_sequence: " + return err(format_underline("parse_escape_sequence: " "invalid token found in UTF-8 codepoint uXXXX.", {{std::addressof(loc), "here"}})); } @@ -346,14 +346,14 @@ result parse_escape_sequence(location& loc) } else { - return err(format_underline("[error] parse_escape_sequence: " + return err(format_underline("parse_escape_sequence: " "invalid token found in UTF-8 codepoint Uxxxxxxxx", {{std::addressof(loc), "here"}})); } } } - const auto msg = format_underline("[error] parse_escape_sequence: " + const auto msg = format_underline("parse_escape_sequence: " "unknown escape sequence appeared.", {{std::addressof(loc), "escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}}, /* Hints = */{"if you want to write backslash as just one backslash, " @@ -378,7 +378,7 @@ parse_ml_basic_string(location& loc) auto delim = lex_ml_basic_string_delim::invoke(inner_loc); if(!delim) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_ml_basic_string: invalid token", {{std::addressof(inner_loc), "should be \"\"\""}}), source_location(std::addressof(inner_loc))); @@ -405,7 +405,7 @@ parse_ml_basic_string(location& loc) } if(inner_loc.iter() == inner_loc.end()) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_ml_basic_string: unexpected end of region", {{std::addressof(inner_loc), "not sufficient token"}}), source_location(std::addressof(inner_loc))); @@ -417,7 +417,7 @@ parse_ml_basic_string(location& loc) else { loc.reset(first); - return err(format_underline("[error] toml::parse_ml_basic_string: " + return err(format_underline("toml::parse_ml_basic_string: " "the next token is not a valid multiline string", {{std::addressof(loc), "here"}})); } @@ -436,7 +436,7 @@ parse_basic_string(location& loc) auto quot = lex_quotation_mark::invoke(inner_loc); if(!quot) { - throw internal_error(format_underline("[error] parse_basic_string: " + throw internal_error(format_underline("parse_basic_string: " "invalid token", {{std::addressof(inner_loc), "should be \""}}), source_location(std::addressof(inner_loc))); } @@ -458,7 +458,7 @@ parse_basic_string(location& loc) } if(inner_loc.iter() == inner_loc.end()) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_basic_string: unexpected end of region", {{std::addressof(inner_loc), "not sufficient token"}}), source_location(std::addressof(inner_loc))); @@ -470,7 +470,7 @@ parse_basic_string(location& loc) else { loc.reset(first); // rollback - return err(format_underline("[error] toml::parse_basic_string: " + return err(format_underline("toml::parse_basic_string: " "the next token is not a valid string", {{std::addressof(loc), "here"}})); } @@ -488,7 +488,7 @@ parse_ml_literal_string(location& loc) const auto open = lex_ml_literal_string_delim::invoke(inner_loc); if(!open) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_ml_literal_string: invalid token", {{std::addressof(inner_loc), "should be '''"}}), source_location(std::addressof(inner_loc))); @@ -501,7 +501,7 @@ parse_ml_literal_string(location& loc) const auto close = lex_ml_literal_string_delim::invoke(inner_loc); if(!close) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_ml_literal_string: invalid token", {{std::addressof(inner_loc), "should be '''"}}), source_location(std::addressof(inner_loc))); @@ -513,7 +513,7 @@ parse_ml_literal_string(location& loc) else { loc.reset(first); // rollback - return err(format_underline("[error] toml::parse_ml_literal_string: " + return err(format_underline("toml::parse_ml_literal_string: " "the next token is not a valid multiline literal string", {{std::addressof(loc), "here"}})); } @@ -531,7 +531,7 @@ parse_literal_string(location& loc) const auto open = lex_apostrophe::invoke(inner_loc); if(!open) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_literal_string: invalid token", {{std::addressof(inner_loc), "should be '"}}), source_location(std::addressof(inner_loc))); @@ -542,7 +542,7 @@ parse_literal_string(location& loc) const auto close = lex_apostrophe::invoke(inner_loc); if(!close) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "parse_literal_string: invalid token", {{std::addressof(inner_loc), "should be '"}}), source_location(std::addressof(inner_loc))); @@ -554,7 +554,7 @@ parse_literal_string(location& loc) else { loc.reset(first); // rollback - return err(format_underline("[error] toml::parse_literal_string: " + return err(format_underline("toml::parse_literal_string: " "the next token is not a valid literal string", {{std::addressof(loc), "here"}})); } @@ -588,7 +588,7 @@ parse_string(location& loc) return parse_literal_string(loc); } } - return err(format_underline("[error] toml::parse_string: ", + return err(format_underline("toml::parse_string: ", {{std::addressof(loc), "the next token is not a string"}})); } @@ -836,7 +836,7 @@ parse_simple_key(location& loc) const auto reg = bare.unwrap(); return ok(std::make_pair(reg.str(), reg)); } - return err(format_underline("[error] toml::parse_simple_key: ", + return err(format_underline("toml::parse_simple_key: ", {{std::addressof(loc), "the next token is not a simple key"}})); } @@ -862,7 +862,7 @@ parse_key(location& loc) } else { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::detail::parse_key: dotted key contains invalid key", {{std::addressof(inner_loc), k.unwrap_err()}}), source_location(std::addressof(inner_loc))); @@ -879,7 +879,7 @@ parse_key(location& loc) } else { - throw internal_error(format_underline("[error] toml::parse_key: " + throw internal_error(format_underline("toml::parse_key: " "dotted key contains invalid key ", {{std::addressof(inner_loc), "should be `.`"}}), source_location(std::addressof(inner_loc))); @@ -895,7 +895,7 @@ parse_key(location& loc) return ok(std::make_pair(std::vector(1, smpl.unwrap().first), smpl.unwrap().second)); } - return err(format_underline("[error] toml::parse_key: ", + return err(format_underline("toml::parse_key: ", {{std::addressof(loc), "is not a valid key"}})); } @@ -913,11 +913,11 @@ parse_array(location& loc) const auto first = loc.iter(); if(loc.iter() == loc.end()) { - return err("[error] toml::parse_array: input is empty"); + return err("toml::parse_array: input is empty"); } if(*loc.iter() != '[') { - return err("[error] toml::parse_array: token is not an array"); + return err("toml::parse_array: token is not an array"); } loc.advance(); @@ -944,7 +944,7 @@ parse_array(location& loc) auto array_start_loc = loc; array_start_loc.reset(first); - throw syntax_error(format_underline("[error] toml::parse_array: " + throw syntax_error(format_underline("toml::parse_array: " "type of elements should be the same each other.", { {std::addressof(array_start_loc), "array starts here"}, { @@ -965,7 +965,7 @@ parse_array(location& loc) auto array_start_loc = loc; array_start_loc.reset(first); - throw syntax_error(format_underline("[error] toml::parse_array: " + throw syntax_error(format_underline("toml::parse_array: " "value having invalid format appeared in an array", { {std::addressof(array_start_loc), "array starts here"}, {std::addressof(loc), "it is not a valid value."} @@ -988,7 +988,7 @@ parse_array(location& loc) auto array_start_loc = loc; array_start_loc.reset(first); - throw syntax_error(format_underline("[error] toml::parse_array:" + throw syntax_error(format_underline("toml::parse_array:" " missing array separator `,` after a value", { {std::addressof(array_start_loc), "array starts here"}, {std::addressof(loc), "should be `,`"} @@ -997,7 +997,7 @@ parse_array(location& loc) } } loc.reset(first); - throw syntax_error(format_underline("[error] toml::parse_array: " + throw syntax_error(format_underline("toml::parse_array: " "array did not closed by `]`", {{std::addressof(loc), "should be closed"}}), source_location(std::addressof(loc))); @@ -1019,7 +1019,7 @@ parse_key_value_pair(location& loc) if(const auto keyval_sep = lex_keyval_sep::invoke(loc)) { loc.reset(first); - msg = format_underline("[error] toml::parse_key_value_pair: " + msg = format_underline("toml::parse_key_value_pair: " "empty key is not allowed.", {{std::addressof(loc), "key expected before '='"}}); } @@ -1035,7 +1035,7 @@ parse_key_value_pair(location& loc) const auto line_end = std::find(loc.iter(), loc.end(), '\n'); if(std::find(loc.iter(), line_end, '=') != line_end) { - msg = format_underline("[error] toml::parse_key_value_pair: " + msg = format_underline("toml::parse_key_value_pair: " "invalid format for key", {{std::addressof(loc), "invalid character in key"}}, {"Did you forget '.' to separate dotted-key?", @@ -1043,7 +1043,7 @@ parse_key_value_pair(location& loc) } else // if not, the error is lack of key-value separator. { - msg = format_underline("[error] toml::parse_key_value_pair: " + msg = format_underline("toml::parse_key_value_pair: " "missing key-value separator `=`", {{std::addressof(loc), "should be `=`"}}); } @@ -1061,7 +1061,7 @@ parse_key_value_pair(location& loc) if(sequence, maybe, lex_newline>::invoke(loc)) { loc.reset(after_kvsp); - msg = format_underline("[error] toml::parse_key_value_pair: " + msg = format_underline("toml::parse_key_value_pair: " "missing value after key-value separator '='", {{std::addressof(loc), "expected value, but got nothing"}}); } @@ -1196,7 +1196,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, { // show special err msg for conflicting table throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: array of table (\"", + "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") cannot be defined"), { {std::addressof(get_region(tab->at(k))), @@ -1208,7 +1208,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, else if(!(tab->at(k).is_array())) { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: array of table (\"", + "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") collides with" " existing value"), { {std::addressof(get_region(tab->at(k))), @@ -1223,7 +1223,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, if(!(a.front().is_table())) { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: array of table (\"", + "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") collides with" " existing value"), { {std::addressof(get_region(tab->at(k))), @@ -1251,7 +1251,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, if(detail::get_region(a.front()).str().substr(0,2) != "[[") { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: array of table (\"", + "toml::insert_value: array of table (\"", format_dotted_keys(first, last), "\") collides with" " existing array-of-tables"), { {std::addressof(get_region(tab->at(k))), @@ -1280,7 +1280,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, tab->at(k), first, iter, last)) { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: table (\"", + "toml::insert_value: table (\"", format_dotted_keys(first, last), "\") already exists."), { {std::addressof(get_region(tab->at(k))), @@ -1308,7 +1308,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, tab->at(k).as_array().front().is_table()) { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: array of tables (\"", + "toml::insert_value: array of tables (\"", format_dotted_keys(first, last), "\") already exists."), { {std::addressof(get_region(tab->at(k))), "array of tables defined here"}, @@ -1319,7 +1319,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, else { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: value (\"", + "toml::insert_value: value (\"", format_dotted_keys(first, last), "\") already exists."), { {std::addressof(get_region(tab->at(k))), "value already exists here"}, @@ -1355,7 +1355,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, if(!a.back().is_table()) { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: target (", + "toml::insert_value: target (", format_dotted_keys(first, std::next(iter)), ") is neither table nor an array of tables"), { {std::addressof(get_region(a.back())), @@ -1368,7 +1368,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, else { throw syntax_error(format_underline(concat_to_string( - "[error] toml::insert_value: target (", + "toml::insert_value: target (", format_dotted_keys(first, std::next(iter)), ") is neither table nor an array of tables"), { {std::addressof(get_region(tab->at(k))), @@ -1392,7 +1392,7 @@ parse_inline_table(location& loc) table_type retval; if(!(loc.iter() != loc.end() && *loc.iter() == '{')) { - return err(format_underline("[error] toml::parse_inline_table: ", + return err(format_underline("toml::parse_inline_table: ", {{std::addressof(loc), "the next token is not an inline table"}})); } loc.advance(); @@ -1421,7 +1421,7 @@ parse_inline_table(location& loc) insert_nested_key(retval, val, keys.begin(), keys.end(), key_reg); if(!inserted) { - throw internal_error("[error] toml::parse_inline_table: " + throw internal_error("toml::parse_inline_table: " "failed to insert value into table: " + inserted.unwrap_err(), source_location(std::addressof(loc))); } @@ -1439,14 +1439,14 @@ parse_inline_table(location& loc) } else if(*loc.iter() == '#' || *loc.iter() == '\r' || *loc.iter() == '\n') { - throw syntax_error(format_underline("[error] " + throw syntax_error(format_underline( "toml::parse_inline_table: missing curly brace `}`", {{std::addressof(loc), "should be `}`"}}), source_location(std::addressof(loc))); } else { - throw syntax_error(format_underline("[error] " + throw syntax_error(format_underline( "toml::parse_inline_table: missing table separator `,` ", {{std::addressof(loc), "should be `,`"}}), source_location(std::addressof(loc))); @@ -1454,7 +1454,7 @@ parse_inline_table(location& loc) } } loc.reset(first); - throw syntax_error(format_underline("[error] toml::parse_inline_table: " + throw syntax_error(format_underline("toml::parse_inline_table: " "inline table did not closed by `}`", {{std::addressof(loc), "should be closed"}}), source_location(std::addressof(loc))); @@ -1480,7 +1480,7 @@ result guess_number_type(const location& l) if(loc.iter() != loc.end() && (*loc.iter() == '+' || *loc.iter() == '-' || *loc.iter() == 'Z' || *loc.iter() == 'z')) { - return err(format_underline("[error] bad offset: should be [+-]HH:MM or Z", + return err(format_underline("bad offset: should be [+-]HH:MM or Z", {{std::addressof(loc), "[+-]HH:MM or Z"}}, {"pass: +09:00, -05:30", "fail: +9:00, -5:30"})); } @@ -1500,14 +1500,14 @@ result guess_number_type(const location& l) const auto c = *loc.iter(); if(c == 'T' || c == 't') { - return err(format_underline("[error] bad time: should be HH:MM:SS.subsec", + return err(format_underline("bad time: should be HH:MM:SS.subsec", {{std::addressof(loc), "HH:MM:SS.subsec"}}, {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", "fail: 1979-05-27T7:32:00, 1979-05-27 17:32"})); } if('0' <= c && c <= '9') { - return err(format_underline("[error] bad time: missing T", + return err(format_underline("bad time: missing T", {{std::addressof(loc), "T or space required here"}}, {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"})); @@ -1516,7 +1516,7 @@ result guess_number_type(const location& l) ('0' <= *std::next(loc.iter()) && *std::next(loc.iter())<= '9')) { loc.advance(); - return err(format_underline("[error] bad time: should be HH:MM:SS.subsec", + return err(format_underline("bad time: should be HH:MM:SS.subsec", {{std::addressof(loc), "HH:MM:SS.subsec"}}, {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999", "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"})); @@ -1533,7 +1533,7 @@ result guess_number_type(const location& l) { if(loc.iter() != loc.end() && *loc.iter() == '_') { - return err(format_underline("[error] bad float: `_` should be surrounded by digits", + return err(format_underline("bad float: `_` should be surrounded by digits", {{std::addressof(loc), "here"}}, {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); @@ -1549,7 +1549,7 @@ result guess_number_type(const location& l) const auto c = *loc.iter(); if(c == '_') { - return err(format_underline("[error] bad integer: `_` should be surrounded by digits", + return err(format_underline("bad integer: `_` should be surrounded by digits", {{std::addressof(loc), "here"}}, {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", "fail: 1__000, 0123"})); @@ -1558,21 +1558,21 @@ result guess_number_type(const location& l) { // leading zero. point '0' loc.retrace(); - return err(format_underline("[error] bad integer: leading zero", + return err(format_underline("bad integer: leading zero", {{std::addressof(loc), "here"}}, {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", "fail: 1__000, 0123"})); } if(c == ':' || c == '-') { - return err(format_underline("[error] bad datetime: invalid format", + return err(format_underline("bad datetime: invalid format", {{std::addressof(loc), "here"}}, {"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z", "fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"})); } if(c == '.' || c == 'e' || c == 'E') { - return err(format_underline("[error] bad float: invalid format", + return err(format_underline("bad float: invalid format", {{std::addressof(loc), "here"}}, {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); @@ -1582,19 +1582,19 @@ result guess_number_type(const location& l) } if(loc.iter() != loc.end() && *loc.iter() == '.') { - return err(format_underline("[error] bad float: invalid format", + return err(format_underline("bad float: invalid format", {{std::addressof(loc), "integer part required before this"}}, {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan", "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"})); } if(loc.iter() != loc.end() && *loc.iter() == '_') { - return err(format_underline("[error] bad number: `_` should be surrounded by digits", + return err(format_underline("bad number: `_` should be surrounded by digits", {{std::addressof(loc), "`_` is not surrounded by digits"}}, {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755", "fail: 1__000, 0123"})); } - return err(format_underline("[error] bad format: unknown value appeared", + return err(format_underline("bad format: unknown value appeared", {{std::addressof(loc), "here"}})); } @@ -1623,7 +1623,7 @@ result parse_value(location& loc) const auto first = loc.iter(); if(first == loc.end()) { - return err(format_underline("[error] toml::parse_value: input is empty", + return err(format_underline("toml::parse_value: input is empty", {{std::addressof(loc), ""}})); } @@ -1646,7 +1646,7 @@ result parse_value(location& loc) case value_t::table : {return parse_inline_table(loc);} default: { - const auto msg = format_underline("[error] toml::parse_value: " + const auto msg = format_underline("toml::parse_value: " "unknown token appeared", {{std::addressof(loc), "unknown"}}); loc.reset(first); return err(msg); @@ -1665,7 +1665,7 @@ parse_table_key(location& loc) const auto open = lex_std_table_open::invoke(inner_loc); if(!open || inner_loc.iter() == inner_loc.end()) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::parse_table_key: no `[`", {{std::addressof(inner_loc), "should be `[`"}}), source_location(std::addressof(inner_loc))); @@ -1676,7 +1676,7 @@ parse_table_key(location& loc) const auto keys = parse_key(inner_loc); if(!keys) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::parse_table_key: invalid key", {{std::addressof(inner_loc), "not key"}}), source_location(std::addressof(inner_loc))); @@ -1687,7 +1687,7 @@ parse_table_key(location& loc) const auto close = lex_std_table_close::invoke(inner_loc); if(!close) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::parse_table_key: no `]`", {{std::addressof(inner_loc), "should be `]`"}}), source_location(std::addressof(inner_loc))); @@ -1701,7 +1701,7 @@ parse_table_key(location& loc) const auto nl = lex_newline_after_table_key::invoke(loc); if(!nl) { - throw syntax_error(format_underline("[error] " + throw syntax_error(format_underline( "toml::parse_table_key: newline required after [table.key]", {{std::addressof(loc), "expected newline"}}), source_location(std::addressof(loc))); @@ -1711,7 +1711,7 @@ parse_table_key(location& loc) } else { - return err(format_underline("[error] toml::parse_table_key: " + return err(format_underline("toml::parse_table_key: " "not a valid table key", {{std::addressof(loc), "here"}})); } } @@ -1727,7 +1727,7 @@ parse_array_table_key(location& loc) const auto open = lex_array_table_open::invoke(inner_loc); if(!open || inner_loc.iter() == inner_loc.end()) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::parse_array_table_key: no `[[`", {{std::addressof(inner_loc), "should be `[[`"}}), source_location(std::addressof(inner_loc))); @@ -1736,7 +1736,7 @@ parse_array_table_key(location& loc) const auto keys = parse_key(inner_loc); if(!keys) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::parse_array_table_key: invalid key", {{std::addressof(inner_loc), "not a key"}}), source_location(std::addressof(inner_loc))); @@ -1745,7 +1745,7 @@ parse_array_table_key(location& loc) const auto close = lex_array_table_close::invoke(inner_loc); if(!close) { - throw internal_error(format_underline("[error] " + throw internal_error(format_underline( "toml::parse_table_key: no `]]`", {{std::addressof(inner_loc), "should be `]]`"}}), source_location(std::addressof(inner_loc))); @@ -1759,7 +1759,7 @@ parse_array_table_key(location& loc) const auto nl = lex_newline_after_table_key::invoke(loc); if(!nl) { - throw syntax_error(format_underline("[error] toml::" + throw syntax_error(format_underline("toml::" "parse_array_table_key: newline required after [[table.key]]", {{std::addressof(loc), "expected newline"}}), source_location(std::addressof(loc))); @@ -1769,7 +1769,7 @@ parse_array_table_key(location& loc) } else { - return err(format_underline("[error] toml::parse_array_table_key: " + return err(format_underline("toml::parse_array_table_key: " "not a valid table key", {{std::addressof(loc), "here"}})); } } @@ -1844,7 +1844,7 @@ parse_ml_table(location& loc) { const auto before2 = loc.iter(); lex_ws::invoke(loc); // skip whitespace - const auto msg = format_underline("[error] toml::parse_table: " + const auto msg = format_underline("toml::parse_table: " "invalid line format", {{std::addressof(loc), concat_to_string( "expected newline, but got '", show_char(*loc.iter()), "'.")}}); loc.reset(before2); diff --git a/toml/value.hpp b/toml/value.hpp index e2f5cf8..64f8b5c 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -32,7 +32,7 @@ template& v) { throw type_error(detail::format_underline(concat_to_string( - "[error] toml::value bad_cast to ", Expected), { + "toml::value: bad_cast to ", Expected), { {std::addressof(get_region(v)), concat_to_string("the actual type is ", actual)} }), v.location()); From 821eb9632bf674798d934c2d14cbe0d425df2863 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 17:59:47 +0900 Subject: [PATCH 04/17] feat: add a macro-dependent constant --- toml/color.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toml/color.hpp b/toml/color.hpp index 514632b..747d0c6 100644 --- a/toml/color.hpp +++ b/toml/color.hpp @@ -3,6 +3,12 @@ #include #include +#ifdef TOML11_COLORIZE_ERROR_MESSAGE +#define TOML11_COLORED_MESSAGE_ACTIVATED true +#else +#define TOML11_COLORED_MESSAGE_ACTIVATED false +#endif + namespace toml { From d47174954fb5c42900dd5e1102e637303f097823 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 18:00:28 +0900 Subject: [PATCH 05/17] feat: colorize user-defined msg by format_error --- toml/value.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/toml/value.hpp b/toml/value.hpp index 64f8b5c..f0fc5ca 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -1843,25 +1843,27 @@ operator>=(const basic_value& lhs, const basic_value& rhs) template class T, template class A> inline std::string format_error(const std::string& err_msg, const basic_value& v, const std::string& comment, - std::vector hints = {}) + std::vector hints = {}, + const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) { return detail::format_underline(err_msg, std::vector>{ {std::addressof(detail::get_region(v)), comment} - }, std::move(hints)); + }, std::move(hints), colorize); } template class T, template class A> inline std::string format_error(const std::string& err_msg, const toml::basic_value& v1, const std::string& comment1, const toml::basic_value& v2, const std::string& comment2, - std::vector hints = {}) + std::vector hints = {}, + const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) { return detail::format_underline(err_msg, std::vector>{ {std::addressof(detail::get_region(v1)), comment1}, {std::addressof(detail::get_region(v2)), comment2} - }, std::move(hints)); + }, std::move(hints), colorize); } template class T, template class A> @@ -1869,14 +1871,15 @@ inline std::string format_error(const std::string& err_msg, const toml::basic_value& v1, const std::string& comment1, const toml::basic_value& v2, const std::string& comment2, const toml::basic_value& v3, const std::string& comment3, - std::vector hints = {}) + std::vector hints = {}, + const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) { return detail::format_underline(err_msg, std::vector>{ {std::addressof(detail::get_region(v1)), comment1}, {std::addressof(detail::get_region(v2)), comment2}, {std::addressof(detail::get_region(v3)), comment3} - }, std::move(hints)); + }, std::move(hints), colorize); } template Date: Wed, 13 Nov 2019 18:01:47 +0900 Subject: [PATCH 06/17] feat: add runtime colorize flag --- toml/region.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index 73fc076..7a55cfb 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -419,7 +419,8 @@ struct region final : public region_base // to show a better error message. inline std::string format_underline(const std::string& message, const std::vector>& reg_com, - const std::vector& helps = {}) + const std::vector& helps = {}, + const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) { assert(!reg_com.empty()); @@ -434,9 +435,10 @@ inline std::string format_underline(const std::string& message, std::ostringstream retval; -#ifdef TOML11_COLORIZE_ERROR_MESSAGE - retval << color::colorize; // turn on ANSI color -#endif + if(colorize) + { + retval << color::colorize; // turn on ANSI color + } retval << color::bold << color::red << "[error] " << color::reset << color::bold << message << color::reset << '\n'; From bbe33e87d99470f2582c7ee1fe3713be61983d12 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 18:05:37 +0900 Subject: [PATCH 07/17] feat: detect [error] prefix duplication --- toml/region.hpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index 7a55cfb..8169342 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -440,8 +440,21 @@ inline std::string format_underline(const std::string& message, retval << color::colorize; // turn on ANSI color } - retval << color::bold << color::red << "[error] " << color::reset - << color::bold << message << color::reset << '\n'; + // XXX + // Here, before `colorize` support, it does not output `[error] ` prefix + // automatically. So some user may output it manually and this change may + // duplicate the prefix. To avoid it, check the first 8 characters and + // if it is "[error] ", it removes that part from the message shown. + if(message.size() > 8 && message.substr(0, 8) == "[error] ") + { + retval << color::bold << color::red << "[error] " << color::reset + << color::bold << message.substr(8) << color::reset << '\n'; + } + else + { + retval << color::bold << color::red << "[error] " << color::reset + << color::bold << message << color::reset << '\n'; + } for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter) { From 571baa2c26f960ab3606765fedc68ad21d9583ce Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 18:08:31 +0900 Subject: [PATCH 08/17] refactor: remove nocolor:: operations since color can be on-off at runtime --- toml/color.hpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/toml/color.hpp b/toml/color.hpp index 747d0c6..479c26a 100644 --- a/toml/color.hpp +++ b/toml/color.hpp @@ -57,28 +57,8 @@ inline std::ostream& white (std::ostream& os) {if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;} } // color_ansi -// do nothing. -namespace nocolor -{ -inline std::ostream& colorize (std::ostream& os) noexcept {return os;} -inline std::ostream& nocolorize(std::ostream& os) noexcept {return os;} -inline std::ostream& reset (std::ostream& os) noexcept {return os;} -inline std::ostream& bold (std::ostream& os) noexcept {return os;} -inline std::ostream& grey (std::ostream& os) noexcept {return os;} -inline std::ostream& red (std::ostream& os) noexcept {return os;} -inline std::ostream& green (std::ostream& os) noexcept {return os;} -inline std::ostream& yellow (std::ostream& os) noexcept {return os;} -inline std::ostream& blue (std::ostream& os) noexcept {return os;} -inline std::ostream& magenta (std::ostream& os) noexcept {return os;} -inline std::ostream& cyan (std::ostream& os) noexcept {return os;} -inline std::ostream& white (std::ostream& os) noexcept {return os;} -} // nocolor - -#ifdef TOML11_COLORIZE_ERROR_MESSAGE +// ANSI escape sequence is the only and default colorization method currently namespace color = color_ansi; -#else -namespace color = nocolor; -#endif } // toml #endif// TOML11_COLOR_HPP From f290390c630fa66713e0bcc35a3ee082134236b9 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 13 Nov 2019 18:14:42 +0900 Subject: [PATCH 09/17] fix: consider the no-space cases like [error]: --- toml/region.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index 8169342..b6ba119 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -441,13 +441,13 @@ inline std::string format_underline(const std::string& message, } // XXX - // Here, before `colorize` support, it does not output `[error] ` prefix + // Here, before `colorize` support, it does not output `[error]` prefix // automatically. So some user may output it manually and this change may - // duplicate the prefix. To avoid it, check the first 8 characters and - // if it is "[error] ", it removes that part from the message shown. - if(message.size() > 8 && message.substr(0, 8) == "[error] ") + // duplicate the prefix. To avoid it, check the first 7 characters and + // if it is "[error]", it removes that part from the message shown. + if(message.size() > 7 && message.substr(0, 7) == "[error]") { - retval << color::bold << color::red << "[error] " << color::reset + retval << color::bold << color::red << "[error]" << color::reset << color::bold << message.substr(8) << color::reset << '\n'; } else From 6f7539dc6a5dd2c6172bf2d56b1ca69abdd55da6 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 14 Nov 2019 15:31:27 +0900 Subject: [PATCH 10/17] fix: deduplicate [error] prefix in the messages --- toml/parser.hpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/toml/parser.hpp b/toml/parser.hpp index be92143..9e511ad 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -312,7 +312,7 @@ result parse_escape_sequence(location& loc) const auto first = loc.iter(); if(first == loc.end() || *first != '\\') { - return err(format_underline("[error]: toml::parse_escape_sequence: ", {{ + return err(format_underline("toml::parse_escape_sequence: ", {{ std::addressof(loc), "the next token is not a backslash \"\\\""}})); } loc.advance(); @@ -604,7 +604,7 @@ parse_local_date(location& loc) const auto y = lex_date_fullyear::invoke(inner_loc); if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_inner_local_date: invalid year format", {{std::addressof(inner_loc), "should be `-`"}}), source_location(std::addressof(inner_loc))); @@ -613,7 +613,7 @@ parse_local_date(location& loc) const auto m = lex_date_month::invoke(inner_loc); if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-') { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_date: invalid month format", {{std::addressof(inner_loc), "should be `-`"}}), source_location(std::addressof(inner_loc))); @@ -622,7 +622,7 @@ parse_local_date(location& loc) const auto d = lex_date_mday::invoke(inner_loc); if(!d) { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_date: invalid day format", {{std::addressof(inner_loc), "here"}}), source_location(std::addressof(inner_loc))); @@ -637,7 +637,7 @@ parse_local_date(location& loc) else { loc.reset(first); - return err(format_underline("[error]: toml::parse_local_date: ", + return err(format_underline("toml::parse_local_date: ", {{std::addressof(loc), "the next token is not a local_date"}})); } } @@ -654,7 +654,7 @@ parse_local_time(location& loc) const auto h = lex_time_hour::invoke(inner_loc); if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_time: invalid year format", {{std::addressof(inner_loc), "should be `:`"}}), source_location(std::addressof(inner_loc))); @@ -663,7 +663,7 @@ parse_local_time(location& loc) const auto m = lex_time_minute::invoke(inner_loc); if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':') { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_time: invalid month format", {{std::addressof(inner_loc), "should be `:`"}}), source_location(std::addressof(inner_loc))); @@ -672,7 +672,7 @@ parse_local_time(location& loc) const auto s = lex_time_second::invoke(inner_loc); if(!s) { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_time: invalid second format", {{std::addressof(inner_loc), "here"}}), source_location(std::addressof(inner_loc))); @@ -709,7 +709,7 @@ parse_local_time(location& loc) { if(before_secfrac != inner_loc.iter()) { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_time: invalid subsecond format", {{std::addressof(inner_loc), "here"}}), source_location(std::addressof(inner_loc))); @@ -720,7 +720,7 @@ parse_local_time(location& loc) else { loc.reset(first); - return err(format_underline("[error]: toml::parse_local_time: ", + return err(format_underline("toml::parse_local_time: ", {{std::addressof(loc), "the next token is not a local_time"}})); } } @@ -736,7 +736,7 @@ parse_local_datetime(location& loc) const auto date = parse_local_date(inner_loc); if(!date || inner_loc.iter() == inner_loc.end()) { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_datetime: invalid datetime format", {{std::addressof(inner_loc), "date, not datetime"}}), source_location(std::addressof(inner_loc))); @@ -744,7 +744,7 @@ parse_local_datetime(location& loc) const char delim = *(inner_loc.iter()); if(delim != 'T' && delim != 't' && delim != ' ') { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_datetime: invalid datetime format", {{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}), source_location(std::addressof(inner_loc))); @@ -753,7 +753,7 @@ parse_local_datetime(location& loc) const auto time = parse_local_time(inner_loc); if(!time) { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_local_datetime: invalid datetime format", {{std::addressof(inner_loc), "invalid time fomrat"}}), source_location(std::addressof(inner_loc))); @@ -765,7 +765,7 @@ parse_local_datetime(location& loc) else { loc.reset(first); - return err(format_underline("[error]: toml::parse_local_datetime: ", + return err(format_underline("toml::parse_local_datetime: ", {{std::addressof(loc), "the next token is not a local_datetime"}})); } } @@ -781,7 +781,7 @@ parse_offset_datetime(location& loc) const auto datetime = parse_local_datetime(inner_loc); if(!datetime || inner_loc.iter() == inner_loc.end()) { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_offset_datetime: invalid datetime format", {{std::addressof(inner_loc), "date, not datetime"}}), source_location(std::addressof(inner_loc))); @@ -803,7 +803,7 @@ parse_offset_datetime(location& loc) } else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z') { - throw internal_error(format_underline("[error]: " + throw internal_error(format_underline( "toml::parse_offset_datetime: invalid datetime format", {{std::addressof(inner_loc), "should be `Z` or `+HH:MM`"}}), source_location(std::addressof(inner_loc))); @@ -814,7 +814,7 @@ parse_offset_datetime(location& loc) else { loc.reset(first); - return err(format_underline("[error]: toml::parse_offset_datetime: ", + return err(format_underline("toml::parse_offset_datetime: ", {{std::addressof(loc), "the next token is not a offset_datetime"}})); } } @@ -1958,7 +1958,7 @@ result parse_toml_file(location& loc) continue; } - return err(format_underline("[error]: toml::parse_toml_file: " + return err(format_underline("toml::parse_toml_file: " "unknown line appeared", {{std::addressof(loc), "unknown format"}})); } From 2fd466a3c34e7e07ab5234cfcf40010b2ef45d48 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 14 Nov 2019 15:32:17 +0900 Subject: [PATCH 11/17] fix: skip only the prefix, keep spaces --- toml/region.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml/region.hpp b/toml/region.hpp index b6ba119..18c5248 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -448,7 +448,7 @@ inline std::string format_underline(const std::string& message, if(message.size() > 7 && message.substr(0, 7) == "[error]") { retval << color::bold << color::red << "[error]" << color::reset - << color::bold << message.substr(8) << color::reset << '\n'; + << color::bold << message.substr(7) << color::reset << '\n'; } else { From 28519f571216eddbb914d4ae16893ed57b7fc26c Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Mon, 2 Dec 2019 17:08:00 +0900 Subject: [PATCH 12/17] doc: add colorize section to README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 56c3f3f..9486428 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ int main() - [Formatting user-defined error messages](#formatting-user-defined-error-messages) - [Obtaining location information](#obtaining-location-information) - [Exceptions](#exceptions) +- [Colorize Error Messages](#colorize-error-messages) - [Serializing TOML data](#serializing-toml-data) - [Underlying types](#underlying-types) - [Unreleased TOML features](#unreleased-toml-features) @@ -1315,6 +1316,14 @@ struct exception : public std::exception It represents where the error occurs. +## Colorize Error Messages + +By `#define TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from +`toml::parse` and `toml::find|get` will be colorized. + +Note that it is hard to see when the message is written in a file, not terminal, +because it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code). + ## Serializing TOML data toml11 enables you to serialize data into toml format. From 4688c235f5f248a695b32d27f60014cbb15be960 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 12 Dec 2019 17:38:29 +0900 Subject: [PATCH 13/17] refactor: rename internal macro value --- toml/color.hpp | 4 ++-- toml/region.hpp | 2 +- toml/value.hpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/toml/color.hpp b/toml/color.hpp index 479c26a..d85a848 100644 --- a/toml/color.hpp +++ b/toml/color.hpp @@ -4,9 +4,9 @@ #include #ifdef TOML11_COLORIZE_ERROR_MESSAGE -#define TOML11_COLORED_MESSAGE_ACTIVATED true +#define TOML11_ERROR_MESSAGE_COLORIZED true #else -#define TOML11_COLORED_MESSAGE_ACTIVATED false +#define TOML11_ERROR_MESSAGE_COLORIZED false #endif namespace toml diff --git a/toml/region.hpp b/toml/region.hpp index 18c5248..3c3f7c1 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -420,7 +420,7 @@ struct region final : public region_base inline std::string format_underline(const std::string& message, const std::vector>& reg_com, const std::vector& helps = {}, - const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { assert(!reg_com.empty()); diff --git a/toml/value.hpp b/toml/value.hpp index a9d2ba4..b5a4e86 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -1861,7 +1861,7 @@ template class T, template clas inline std::string format_error(const std::string& err_msg, const basic_value& v, const std::string& comment, std::vector hints = {}, - const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { return detail::format_underline(err_msg, std::vector>{ @@ -1874,7 +1874,7 @@ inline std::string format_error(const std::string& err_msg, const toml::basic_value& v1, const std::string& comment1, const toml::basic_value& v2, const std::string& comment2, std::vector hints = {}, - const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { return detail::format_underline(err_msg, std::vector>{ @@ -1889,7 +1889,7 @@ inline std::string format_error(const std::string& err_msg, const toml::basic_value& v2, const std::string& comment2, const toml::basic_value& v3, const std::string& comment3, std::vector hints = {}, - const bool colorize = TOML11_COLORED_MESSAGE_ACTIVATED) + const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED) { return detail::format_underline(err_msg, std::vector>{ From d48d454a61a711c41c4dee4ed66c5d14e731f63f Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 12 Dec 2019 17:55:20 +0900 Subject: [PATCH 14/17] doc: modify README a bit --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9bf0836..3db66b1 100644 --- a/README.md +++ b/README.md @@ -1357,10 +1357,11 @@ It represents where the error occurs. ## Colorize Error Messages -By `#define TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from -`toml::parse` and `toml::find|get` will be colorized. +By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from +`toml::parse` and `toml::find|get` will be colorized. By default, this feature +is turned off. -Note that it is hard to see when the message is written in a file, not terminal, +Note that the message would be messy when it is written to a file, not a terminal because it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code). ## Serializing TOML data From f4ac286b0f9570b697b5e85c46d57b6e9c37b911 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 12 Dec 2019 21:31:21 +0900 Subject: [PATCH 15/17] doc: add description about format_error --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3db66b1..b9d5d31 100644 --- a/README.md +++ b/README.md @@ -1361,8 +1361,23 @@ By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from `toml::parse` and `toml::find|get` will be colorized. By default, this feature is turned off. -Note that the message would be messy when it is written to a file, not a terminal -because it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code). +The message would be messy when it is written to a file, not a terminal because +it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code). + +Without `TOML11_COLORIZE_ERROR_MESSAGE`, you can still colorize user-defined +error message by passing `true` to the `toml::format_error` function. +If you define `TOML11_COLORIZE_ERROR_MESSAGE`, the value is `true` by default. +If not, the defalut value would be `false`. + +```cpp +std::cerr << toml::format_error("[error] value should be positive", + data.at("num"), "positive number required", + hints, /*colorize = */ true) << std::endl; +``` + +Note: It colorize `[error]` in red. That means that it detects `[error]` prefix +at the front of the error message. If there is no `[error]` prefix, +`format_error` adds it to the error message. ## Serializing TOML data From a945bd6eaceafc2897f2ad9d67655114154541a2 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 13 Dec 2019 16:47:33 +0900 Subject: [PATCH 16/17] ci: pass TOML11_COLORIZE_ERROR_MESSAGE on CircleCI --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2db5ab3..0867ff4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ jobs: command: | g++ --version cd tests/ - g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test + g++ -std=c++11 -O2 -Wall -Wextra -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_toml_test.cpp -o check_toml_test go get github.com/BurntSushi/toml-test $GOPATH/bin/toml-test ./check_toml_test test_serialization: @@ -24,7 +24,7 @@ jobs: command: | g++ --version cd tests/ - g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check_serialization.cpp -o check_serialization + g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_serialization.cpp -o check_serialization git clone https://github.com/BurntSushi/toml-test.git cp check_serialization toml-test/tests/valid cd toml-test/tests/valid @@ -47,7 +47,7 @@ jobs: command: | g++ --version cd tests/ - g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check.cpp -o check + g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check.cpp -o check git clone https://github.com/BurntSushi/toml-test.git cp check toml-test/tests/invalid cp check toml-test/tests/valid From 08bf5ffbdfd8df51f61ba882114cc75b639713e8 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Fri, 13 Dec 2019 17:18:32 +0900 Subject: [PATCH 17/17] doc: put screenshot to colorize-error-message --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index b9d5d31..20537ba 100644 --- a/README.md +++ b/README.md @@ -1361,6 +1361,39 @@ By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from `toml::parse` and `toml::find|get` will be colorized. By default, this feature is turned off. +With the following toml file taken from `toml-lang/toml/tests/hard_example.toml`, + +```toml +[error] +array = [ + "This might most likely happen in multiline arrays", + Like here, + "or here, + and here" + ] End of array comment, forgot the # +``` + +the error message would be like this. + +![error-message-1](https://github.com/ToruNiina/toml11/blob/misc/misc/toml11-err-msg-1.png) + +With the following, + +```toml +[error] +# array = [ +# "This might most likely happen in multiline arrays", +# Like here, +# "or here, +# and here" +# ] End of array comment, forgot the # +number = 3.14 pi <--again forgot the # +``` + +the error message would be like this. + +![error-message-2](https://github.com/ToruNiina/toml11/blob/misc/misc/toml11-err-msg-2.png) + The message would be messy when it is written to a file, not a terminal because it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code).