-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add color format_to overloads #1843
Conversation
2a04a32
to
2b66f74
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR.
include/fmt/color.h
Outdated
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with | ||
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a copy-paste? I don't think it is correct.
include/fmt/color.h
Outdated
|
||
std::vector<char> out; | ||
fmt::format_to(std::back_inserter(out), | ||
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); \endrst |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put \endrst
on a separate line.
template <typename OutputIt, typename S, typename Char = char_t<S>, | ||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value)> | ||
OutputIt vformat_to( | ||
OutputIt out, const text_style& ts, const S& format_str, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
S should be replaced with basic_string_view
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
S can't be replaced because basic_string_view
is missing an implicit constructor for a fixed size arrays like const char(&)[5]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't matter. format_to
should convert S
into basic_string_view
when calling this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like to_string_view
can convert more types than the basic_string_view
constructor.
In that case the basic_string_view
constructor needs to be aligned with to_string_view
or we need to rely on to_string_view
to convert it for us. Replacing const S&
with basic_string_view
will lead to build failures otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use to_string_view
.
include/fmt/color.h
Outdated
template <typename S, typename... Args, size_t SIZE = inline_buffer_size, | ||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | ||
inline typename buffer_context<Char>::iterator format_to( | ||
basic_memory_buffer<Char, SIZE>& buf, const text_style& ts, | ||
const S& format_str, Args&&... args) { | ||
basic_format_args<buffer_context<type_identity_t<Char>>> store = | ||
fmt::make_args_checked<Args...>(format_str, args...); | ||
detail::vformat_to(buf, ts, to_string_view(format_str), store); | ||
return detail::buffer_appender<Char>(buf); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is necessary. Please remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your feedback. I corrected my PR accordingly.
I really would like to keep this overload though, mainly it is the main reason why I submitted this PR.
This overload integrates well into a struct fmt::formatter<
specializations for custom types,
it is also possible to colorize only parts of a string and for multiple colorized parts a memory allocation adds up fast.
Otherwise we would have to use the output iterator overload for writing into a memory_buffer
although the private color API accepts a memory_buffer
already but is inaccessible. This would add unneccessary code overhead (and probably adds a performance overhead too).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This overload is redundant because it's equivalent to passing back_insert_iterator to memory_buffer. There should be no overhead.
test/color-test.cc
Outdated
struct ColorFunctionPrintTag {}; | ||
struct ColorFunctionFormatTag {}; | ||
struct ColorFunctionFormatToOutputTag {}; | ||
struct ColorFunctionFormatToNTag {}; | ||
struct ColorFunctionFormatToBufferTag {}; | ||
|
||
template <typename T> struct ColorsTest; | ||
template <> struct ColorsTest<ColorFunctionPrintTag> : public testing::Test { | ||
virtual ~ColorsTest(); | ||
|
||
template <typename... Args> | ||
void expect_color(const std::string& expected, const fmt::text_style& ts, | ||
Args&&... args) { | ||
EXPECT_WRITE(stdout, fmt::print(stdout, ts, std::forward<Args>(args)...), | ||
expected); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an overkill - please leave the old tests as is and add two test cases that check the new APIs.
840b114
to
c0f3fb3
Compare
@vitaut I'm encountering some strange unit test failures on travis (after I've changed back the unit tests to the original style) with some GCC compilers (GCC-6+) that fail to format
https://travis-ci.org/github/fmtlib/fmt/jobs/723128246#L747-L761 I'm using a helper funtion as following: template <typename S, typename... Args,
typename String = std::basic_string<fmt::char_t<S>>>
String format_to_out_helper(const fmt::text_style& ts, const S& format_str,
Args&&... args) {
String out;
fmt::format_to(std::back_inserter(out), ts, format_str,
std::forward<Args>(args)...);
return out;
}
// ....
EXPECT_EQ(format_to_out_helper(fg(fmt::terminal_color::red), "{}", "foo"),
"\x1b[31mfoo\x1b[0m"); The other functions for colorization seem fine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly looks good but please use basic_string_view in format_to. Also there is no need to copy all the tests because all methods share the same implementation. It's enough to do basic sanity test that format_to and vformat_to accept text styles. Then helper functions can go away.
* Fix variable size basic_memory_buffer colorization * Fix an unused arguments warning on GCC that blocks the CI otherwise * Ref fmtlib#1842 * Ref fmtlib#1593
I reduced the test cases as requested and now it only does basic tests whether the API accepts If I understand you right about template <typename S, typename... Args, size_t SIZE = inline_buffer_size,
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
inline typename buffer_context<Char>::iterator format_to(
basic_memory_buffer<Char, SIZE>& buf, const text_style& ts,
const S& format_str, Args&&... args) {
detail::vformat_to(buf, ts, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
return detail::buffer_appender<Char>(buf);
} by template <typename Char, typename... Args, size_t SIZE = inline_buffer_size>
inline typename buffer_context<Char>::iterator format_to(
basic_memory_buffer<Char, SIZE>& buf, const text_style& ts,
basic_string_view<Char> format_str, Args&&... args) {
detail::vformat_to(buf, ts, format_str,
fmt::make_args_checked<Args...>(format_str, args...));
return detail::buffer_appender<Char>(buf);
} which is, from my point of view, not possible because as mentioned above the I attached you my compiler output which could further explain my arguments:
|
Unfortunately those are not good examples and need to change too eventually. We shouldn't repeat the same mistakes in new code. |
Merged in bff4d18 with minor tweaks. Thanks again. |
Thank you for merging this PR partially. The The transfer to Calling the API for colorization is now also unintentional because the non Additionally colorization can't be used easily anymore in |
It can easily be made equivalent if it's not already. The main point is that extra overload is redundant and shouldn't be there.
That's fine. The other overload is there mostly for historical reasons.
This is not the case because formatter specialization use iterators. |
Ok, I see your point now. Overall the overload is not equal for |
This is only because there is a missing |
I have to revert my previous statement. template <typename OutputIt, typename T, typename Traits>
void iterator_buffer<OutputIt, T, Traits>::flush() {
out_ = std::copy_n(data_, this->limit(this->size()), out_);
this->clear();
} The (buffered) data is handed to the output one by one theoretically. Without it, every output iterator accepting API will never be equal to the same API using a Mapping a What could fix this issue is to add support for an output iterator accepting a range of |
It is possible and already implemented in {fmt} with a minor caveat mentioned earlier. |
detail::buffer
to also acceptiterator_buffer
, and non default internal size memory buffers. Size limited buffers are not supported (and also not accepted by the public API). This is whyformat_to_n
is not added as part of this change. Additionally since a colorized string is not an atomic unit per character anymore (because it can't be split in the middle of the ansi color code effectively) it doesnt make sence to add support forformat_to_n
anyway.I agree that my contributions are licensed under the {fmt} license, and agree to future changes to the licensing.