diff --git a/.github/actions/spell-check/dictionary/apis.txt b/.github/actions/spell-check/dictionary/apis.txt
index 3b42555054..1e33da10d7 100644
--- a/.github/actions/spell-check/dictionary/apis.txt
+++ b/.github/actions/spell-check/dictionary/apis.txt
@@ -1,15 +1,17 @@
ACCEPTFILES
ACCESSDENIED
+alignof
bitfield
bitfields
CLASSNOTAVAILABLE
EXPCMDFLAGS
EXPCMDSTATE
fullkbd
+futex
href
IAsync
-IBox
IBind
+IBox
IClass
IComparable
ICustom
@@ -19,7 +21,9 @@ IExplorer
IMap
IObject
IStorage
+llabs
LCID
+lround
LSHIFT
NCHITTEST
NCLBUTTONDBLCLK
@@ -28,9 +32,17 @@ NOAGGREGATION
NOREDIRECTIONBITMAP
oaidl
ocidl
+otms
+OUTLINETEXTMETRICW
+PAGESCROLL
RETURNCMD
rfind
roundf
RSHIFT
+rx
SIZENS
+spsc
+STDCPP
+syscall
tmp
+tx
diff --git a/.github/actions/spell-check/dictionary/microsoft.txt b/.github/actions/spell-check/dictionary/microsoft.txt
index 5e5d2ee316..ef2c23c5ab 100644
--- a/.github/actions/spell-check/dictionary/microsoft.txt
+++ b/.github/actions/spell-check/dictionary/microsoft.txt
@@ -1,4 +1,5 @@
ACLs
+altform
backplating
DACL
DACLs
@@ -9,7 +10,9 @@ microsoftonline
osgvsowi
powerrename
powershell
+pscustomobject
SACLs
tdbuildteamid
vcruntime
visualstudio
+wslpath
diff --git a/.github/actions/spell-check/expect/expect.txt b/.github/actions/spell-check/expect/expect.txt
index 47a511eefa..01b64c42d7 100644
--- a/.github/actions/spell-check/expect/expect.txt
+++ b/.github/actions/spell-check/expect/expect.txt
@@ -594,6 +594,7 @@ devops
Dext
df
DFactory
+DFMT
dh
dialogbox
diffing
@@ -1082,6 +1083,8 @@ INITCOMMONCONTROLSEX
INITDIALOG
initguid
INITMENU
+imagemagick
+inkscape
inl
INLINEPREFIX
Inlines
@@ -1529,6 +1532,7 @@ nothrow
NOTICKS
NOTIMPL
notin
+NOTOPMOST
NOTNULL
NOTRACK
NOTSUPPORTED
@@ -2133,6 +2137,7 @@ SIGDN
SINGLEFLAG
SINGLETHREADED
siup
+SIZEBOX
sizeof
SIZESCROLL
SKIPFONT
@@ -2263,6 +2268,7 @@ targetentrypoint
TARGETLIBS
TARGETNAME
targetnametoken
+targetsize
targetver
taskbar
tbar
diff --git a/.github/actions/spell-check/patterns/patterns.txt b/.github/actions/spell-check/patterns/patterns.txt
index 413709e120..f8c3d65534 100644
--- a/.github/actions/spell-check/patterns/patterns.txt
+++ b/.github/actions/spell-check/patterns/patterns.txt
@@ -19,3 +19,4 @@ TestUtils::VerifyExpectedString\(tb, L"[^"]+"
Base64::s_(?:En|De)code\(L"[^"]+"
VERIFY_ARE_EQUAL\(L"[^"]+"
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+/"
+std::memory_order_[\w]+
diff --git a/NuGet.Config b/NuGet.Config
index de105e187b..00b1de60c4 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -8,7 +8,7 @@
-
+
+
+[#1337]: https://github.com/microsoft/terminal/issues/1337
+[#3789]: https://github.com/microsoft/terminal/issues/3789
+[#3327]: https://github.com/microsoft/terminal/issues/3327
+[#5772]: https://github.com/microsoft/terminal/pull/5772
diff --git a/doc/specs/#1337 - Per-Profile Tab Colors/profile-tabColor-000.gif b/doc/specs/#1337 - Per-Profile Tab Colors/profile-tabColor-000.gif
new file mode 100644
index 0000000000..2b3e04a651
Binary files /dev/null and b/doc/specs/#1337 - Per-Profile Tab Colors/profile-tabColor-000.gif differ
diff --git a/oss/fmt/cgmanifest.json b/oss/fmt/cgmanifest.json
index a8148d03ab..1a8c5d01b1 100644
--- a/oss/fmt/cgmanifest.json
+++ b/oss/fmt/cgmanifest.json
@@ -4,7 +4,7 @@
"type": "git",
"git": {
"repositoryUrl": "https://github.com/fmtlib/fmt",
- "commitHash": "9bdd1596cef1b57b9556f8bef32dc4a32322ef3e"
+ "commitHash": "f19b1a521ee8b606dedcadfda69fd10ddf882753"
}
}
}
diff --git a/oss/fmt/include/fmt/chrono.h b/oss/fmt/include/fmt/chrono.h
index 421d464ad8..e70b8053a6 100644
--- a/oss/fmt/include/fmt/chrono.h
+++ b/oss/fmt/include/fmt/chrono.h
@@ -48,7 +48,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// From fits in To without any problem.
} else {
// From does not always fit in To, resort to a dynamic check.
- if (from < T::min() || from > T::max()) {
+ if (from < (T::min)() || from > (T::max)()) {
// outside range.
ec = 1;
return {};
@@ -74,7 +74,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
if (F::is_signed && !T::is_signed) {
// From may be negative, not allowed!
- if (fmt::internal::is_negative(from)) {
+ if (fmt::detail::is_negative(from)) {
ec = 1;
return {};
}
@@ -84,7 +84,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// yes, From always fits in To.
} else {
// from may not fit in To, we have to do a dynamic check
- if (from > static_cast(T::max())) {
+ if (from > static_cast((T::max)())) {
ec = 1;
return {};
}
@@ -97,7 +97,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
// yes, From always fits in To.
} else {
// from may not fit in To, we have to do a dynamic check
- if (from > static_cast(T::max())) {
+ if (from > static_cast((T::max)())) {
// outside range.
ec = 1;
return {};
@@ -141,7 +141,7 @@ FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
// catch the only happy case
if (std::isfinite(from)) {
- if (from >= T::lowest() && from <= T::max()) {
+ if (from >= T::lowest() && from <= (T::max)()) {
return static_cast(from);
}
// not within range.
@@ -195,12 +195,13 @@ To safe_duration_cast(std::chrono::duration from,
}
// multiply with Factor::num without overflow or underflow
if (Factor::num != 1) {
- const auto max1 = internal::max_value() / Factor::num;
+ const auto max1 = detail::max_value() / Factor::num;
if (count > max1) {
ec = 1;
return {};
}
- const auto min1 = std::numeric_limits::min() / Factor::num;
+ const auto min1 =
+ (std::numeric_limits::min)() / Factor::num;
if (count < min1) {
ec = 1;
return {};
@@ -269,7 +270,7 @@ To safe_duration_cast(std::chrono::duration from,
// multiply with Factor::num without overflow or underflow
if (Factor::num != 1) {
- constexpr auto max1 = internal::max_value() /
+ constexpr auto max1 = detail::max_value() /
static_cast(Factor::num);
if (count > max1) {
ec = 1;
@@ -306,12 +307,12 @@ To safe_duration_cast(std::chrono::duration from,
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO
-namespace internal {
+namespace detail {
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
-} // namespace internal
+} // namespace detail
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
@@ -322,22 +323,22 @@ inline std::tm localtime(std::time_t time) {
dispatcher(std::time_t t) : time_(t) {}
bool run() {
- using namespace fmt::internal;
+ using namespace fmt::detail;
return handle(localtime_r(&time_, &tm_));
}
bool handle(std::tm* tm) { return tm != nullptr; }
- bool handle(internal::null<>) {
- using namespace fmt::internal;
+ bool handle(detail::null<>) {
+ using namespace fmt::detail;
return fallback(localtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
- bool fallback(internal::null<>) {
- using namespace fmt::internal;
+ bool fallback(detail::null<>) {
+ using namespace fmt::detail;
std::tm* tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != nullptr;
@@ -359,21 +360,21 @@ inline std::tm gmtime(std::time_t time) {
dispatcher(std::time_t t) : time_(t) {}
bool run() {
- using namespace fmt::internal;
+ using namespace fmt::detail;
return handle(gmtime_r(&time_, &tm_));
}
bool handle(std::tm* tm) { return tm != nullptr; }
- bool handle(internal::null<>) {
- using namespace fmt::internal;
+ bool handle(detail::null<>) {
+ using namespace fmt::detail;
return fallback(gmtime_s(&tm_, &time_));
}
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
- bool fallback(internal::null<>) {
+ bool fallback(detail::null<>) {
std::tm* tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
return tm != nullptr;
@@ -386,17 +387,17 @@ inline std::tm gmtime(std::time_t time) {
return gt.tm_;
}
-namespace internal {
-inline std::size_t strftime(char* str, std::size_t count, const char* format,
- const std::tm* time) {
+namespace detail {
+inline size_t strftime(char* str, size_t count, const char* format,
+ const std::tm* time) {
return std::strftime(str, count, format, time);
}
-inline std::size_t strftime(wchar_t* str, std::size_t count,
- const wchar_t* format, const std::tm* time) {
+inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
+ const std::tm* time) {
return std::wcsftime(str, count, format, time);
}
-} // namespace internal
+} // namespace detail
template struct formatter {
template
@@ -405,7 +406,7 @@ template struct formatter {
if (it != ctx.end() && *it == ':') ++it;
auto end = it;
while (end != ctx.end() && *end != '}') ++end;
- tm_format.reserve(internal::to_unsigned(end - it + 1));
+ tm_format.reserve(detail::to_unsigned(end - it + 1));
tm_format.append(it, end);
tm_format.push_back('\0');
return end;
@@ -414,11 +415,10 @@ template struct formatter {
template
auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
basic_memory_buffer buf;
- std::size_t start = buf.size();
+ size_t start = buf.size();
for (;;) {
- std::size_t size = buf.capacity() - start;
- std::size_t count =
- internal::strftime(&buf[start], size, &tm_format[0], &tm);
+ size_t size = buf.capacity() - start;
+ size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm);
if (count != 0) {
buf.resize(start + count);
break;
@@ -430,7 +430,7 @@ template struct formatter {
// https://github.com/fmtlib/fmt/issues/367
break;
}
- const std::size_t MIN_GROWTH = 10;
+ const size_t MIN_GROWTH = 10;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return std::copy(buf.begin(), buf.end(), ctx.out());
@@ -439,7 +439,7 @@ template struct formatter {
basic_memory_buffer tm_format;
};
-namespace internal {
+namespace detail {
template FMT_CONSTEXPR const char* get_units() {
return nullptr;
}
@@ -768,19 +768,25 @@ OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
return format_to(out, std::is_floating_point::value ? fp_f : format,
val);
}
+template
+OutputIt copy_unit(string_view unit, OutputIt out, Char) {
+ return std::copy(unit.begin(), unit.end(), out);
+}
+
+template
+OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) {
+ // This works when wchar_t is UTF-32 because units only contain characters
+ // that have the same representation in UTF-16 and UTF-32.
+ utf8_to_utf16 u(unit);
+ return std::copy(u.c_str(), u.c_str() + u.size(), out);
+}
template
OutputIt format_duration_unit(OutputIt out) {
- if (const char* unit = get_units()) {
- string_view s(unit);
- if (const_check(std::is_same())) {
- utf8_to_utf16 u(s);
- return std::copy(u.c_str(), u.c_str() + u.size(), out);
- }
- return std::copy(s.begin(), s.end(), out);
- }
+ if (const char* unit = get_units())
+ return copy_unit(string_view(unit), out, Char());
const Char num_f[] = {'[', '{', '}', ']', 's', 0};
- if (Period::den == 1) return format_to(out, num_f, Period::num);
+ if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num);
const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0};
return format_to(out, num_def_f, Period::num, Period::den);
}
@@ -874,9 +880,9 @@ struct chrono_formatter {
if (isnan(value)) return write_nan();
uint32_or_64_or_128_t n =
to_unsigned(to_nonnegative_int(value, max_value()));
- int num_digits = internal::count_digits(n);
+ int num_digits = detail::count_digits(n);
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
- out = format_decimal(out, n, num_digits);
+ out = format_decimal(out, n, num_digits).end;
}
void write_nan() { std::copy_n("nan", 3, out); }
@@ -1004,14 +1010,14 @@ struct chrono_formatter {
out = format_duration_unit(out);
}
};
-} // namespace internal
+} // namespace detail
template
struct formatter, Char> {
private:
basic_format_specs specs;
int precision;
- using arg_ref_type = internal::arg_ref;
+ using arg_ref_type = detail::arg_ref;
arg_ref_type width_ref;
arg_ref_type precision_ref;
mutable basic_string_view format_str;
@@ -1032,7 +1038,7 @@ struct formatter, Char> {
return arg_ref_type(arg_id);
}
- FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
+ FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) {
return arg_ref_type(context.next_arg_id());
}
@@ -1062,17 +1068,17 @@ struct formatter, Char> {
auto begin = ctx.begin(), end = ctx.end();
if (begin == end || *begin == '}') return {begin, begin};
spec_handler handler{*this, ctx, format_str};
- begin = internal::parse_align(begin, end, handler);
+ begin = detail::parse_align(begin, end, handler);
if (begin == end) return {begin, begin};
- begin = internal::parse_width(begin, end, handler);
+ begin = detail::parse_width(begin, end, handler);
if (begin == end) return {begin, begin};
if (*begin == '.') {
if (std::is_floating_point::value)
- begin = internal::parse_precision(begin, end, handler);
+ begin = detail::parse_precision(begin, end, handler);
else
handler.on_error("precision not allowed for this argument type");
}
- end = parse_chrono_format(begin, end, internal::chrono_format_checker());
+ end = parse_chrono_format(begin, end, detail::chrono_format_checker());
return {begin, end};
}
@@ -1083,7 +1089,7 @@ struct formatter, Char> {
-> decltype(ctx.begin()) {
auto range = do_parse(ctx);
format_str = basic_string_view(
- &*range.begin, internal::to_unsigned(range.end - range.begin));
+ &*range.begin, detail::to_unsigned(range.end - range.begin));
return range.end;
}
@@ -1094,23 +1100,21 @@ struct formatter, Char> {
// is not specified.
basic_memory_buffer buf;
auto out = std::back_inserter(buf);
- using range = internal::output_range;
- internal::basic_writer w(range(ctx.out()));
- internal::handle_dynamic_spec(specs.width,
- width_ref, ctx);
- internal::handle_dynamic_spec(
- precision, precision_ref, ctx);
+ detail::handle_dynamic_spec(specs.width, width_ref,
+ ctx);
+ detail::handle_dynamic_spec(precision,
+ precision_ref, ctx);
if (begin == end || *begin == '}') {
- out = internal::format_duration_value(out, d.count(), precision);
- internal::format_duration_unit(out);
+ out = detail::format_duration_value(out, d.count(), precision);
+ detail::format_duration_unit(out);
} else {
- internal::chrono_formatter f(
+ detail::chrono_formatter f(
ctx, out, d);
f.precision = precision;
parse_chrono_format(begin, end, f);
}
- w.write(buf.data(), buf.size(), specs);
- return w.out();
+ return detail::write(
+ ctx.out(), basic_string_view(buf.data(), buf.size()), specs);
}
};
diff --git a/oss/fmt/include/fmt/color.h b/oss/fmt/include/fmt/color.h
index 96d9ab6b43..b65f892afc 100644
--- a/oss/fmt/include/fmt/color.h
+++ b/oss/fmt/include/fmt/color.h
@@ -198,7 +198,7 @@ struct rgb {
uint8_t b;
};
-namespace internal {
+namespace detail {
// color is a struct of either a rgb color or a terminal color.
struct color_type {
@@ -221,7 +221,7 @@ struct color_type {
uint32_t rgb_color;
} value;
};
-} // namespace internal
+} // namespace detail
// Experimental text formatting support.
class text_style {
@@ -298,11 +298,11 @@ class text_style {
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
return static_cast(ems) != 0;
}
- FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
return foreground_color;
}
- FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
FMT_ASSERT(has_background(), "no background specified for this style");
return background_color;
}
@@ -313,7 +313,7 @@ class text_style {
private:
FMT_CONSTEXPR text_style(bool is_foreground,
- internal::color_type text_color) FMT_NOEXCEPT
+ detail::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
@@ -326,23 +326,23 @@ class text_style {
}
}
- friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
+ friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
FMT_NOEXCEPT;
- friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
+ friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
FMT_NOEXCEPT;
- internal::color_type foreground_color;
- internal::color_type background_color;
+ detail::color_type foreground_color;
+ detail::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
-FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
+FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/true, foreground);
}
-FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
+FMT_CONSTEXPR text_style bg(detail::color_type background) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/false, background);
}
@@ -350,21 +350,21 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
return text_style(lhs) | rhs;
}
-namespace internal {
+namespace detail {
template struct ansi_color_escape {
- FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
+ FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
const char* esc) FMT_NOEXCEPT {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
- bool is_background = esc == internal::data::background_color;
+ bool is_background = esc == detail::data::background_color;
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background) value += 10u;
- std::size_t index = 0;
+ size_t index = 0;
buffer[index++] = static_cast('\x1b');
buffer[index++] = static_cast('[');
@@ -398,7 +398,7 @@ template struct ansi_color_escape {
if (em_bits & static_cast(emphasis::strikethrough))
em_codes[3] = 9;
- std::size_t index = 0;
+ size_t index = 0;
for (int i = 0; i < 4; ++i) {
if (!em_codes[i]) continue;
buffer[index++] = static_cast('\x1b');
@@ -429,14 +429,14 @@ template struct ansi_color_escape {
template
FMT_CONSTEXPR ansi_color_escape make_foreground_color(
- internal::color_type foreground) FMT_NOEXCEPT {
- return ansi_color_escape(foreground, internal::data::foreground_color);
+ detail::color_type foreground) FMT_NOEXCEPT {
+ return ansi_color_escape(foreground, detail::data::foreground_color);
}
template
FMT_CONSTEXPR ansi_color_escape make_background_color(
- internal::color_type background) FMT_NOEXCEPT {
- return ansi_color_escape(background, internal::data::background_color);
+ detail::color_type background) FMT_NOEXCEPT {
+ return ansi_color_escape(background, detail::data::background_color);
}
template
@@ -455,11 +455,11 @@ inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
}
template inline void reset_color(FILE* stream) FMT_NOEXCEPT {
- fputs(internal::data::reset_color, stream);
+ fputs(detail::data::reset_color, stream);
}
template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
- fputs(internal::data::wreset_color, stream);
+ fputs(detail::data::wreset_color, stream);
}
template
@@ -476,33 +476,31 @@ void vformat_to(basic_memory_buffer& buf, const text_style& ts,
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
- auto emphasis = internal::make_emphasis(ts.get_emphasis());
+ auto emphasis = detail::make_emphasis(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
}
if (ts.has_foreground()) {
has_style = true;
- auto foreground =
- internal::make_foreground_color(ts.get_foreground());
+ auto foreground = detail::make_foreground_color(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
}
if (ts.has_background()) {
has_style = true;
- auto background =
- internal::make_background_color(ts.get_background());
+ auto background = detail::make_background_color(ts.get_background());
buf.append(background.begin(), background.end());
}
- internal::vformat_to(buf, format_str, args);
- if (has_style) internal::reset_color(buf);
+ detail::vformat_to(buf, format_str, args);
+ if (has_style) detail::reset_color(buf);
}
-} // namespace internal
+} // namespace detail
template >
void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args> args) {
basic_memory_buffer buf;
- internal::vformat_to(buf, ts, to_string_view(format), args);
+ detail::vformat_to(buf, ts, to_string_view(format), args);
buf.push_back(Char(0));
- internal::fputs(buf.data(), f);
+ detail::fputs(buf.data(), f);
}
/**
@@ -513,10 +511,10 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template ::value)>
+ FMT_ENABLE_IF(detail::is_string::value)>
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
- internal::check_format_string(format_str);
+ detail::check_format_string(format_str);
using context = buffer_context>;
format_arg_store as{args...};
vprint(f, ts, format_str, basic_format_args(as));
@@ -530,7 +528,7 @@ void print(std::FILE* f, const text_style& ts, const S& format_str,
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template ::value)>
+ FMT_ENABLE_IF(detail::is_string::value)>
void print(const text_style& ts, const S& format_str, const Args&... args) {
return print(stdout, ts, format_str, args...);
}
@@ -540,7 +538,7 @@ inline std::basic_string vformat(
const text_style& ts, const S& format_str,
basic_format_args>> args) {
basic_memory_buffer buf;
- internal::vformat_to(buf, ts, to_string_view(format_str), args);
+ detail::vformat_to(buf, ts, to_string_view(format_str), args);
return fmt::to_string(buf);
}
@@ -560,7 +558,7 @@ template >
inline std::basic_string format(const text_style& ts, const S& format_str,
const Args&... args) {
return vformat(ts, to_string_view(format_str),
- internal::make_args_checked(format_str, args...));
+ detail::make_args_checked(format_str, args...));
}
FMT_END_NAMESPACE
diff --git a/oss/fmt/include/fmt/compile.h b/oss/fmt/include/fmt/compile.h
index e4b12f349e..d7e6449ebb 100644
--- a/oss/fmt/include/fmt/compile.h
+++ b/oss/fmt/include/fmt/compile.h
@@ -13,7 +13,33 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
-namespace internal {
+namespace detail {
+
+// A compile-time string which is compiled into fast formatting code.
+class compiled_string {};
+
+template
+struct is_compiled_string : std::is_base_of {};
+
+/**
+ \rst
+ Converts a string literal *s* into a format string that will be parsed at
+ compile time and converted into efficient formatting code. Requires C++17
+ ``constexpr if`` compiler support.
+
+ **Example**::
+
+ // Converts 42 into std::string using the most efficient method and no
+ // runtime format string processing.
+ std::string s = fmt::format(FMT_COMPILE("{}"), 42);
+ \endrst
+ */
+#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
+
+template
+const T& first(const T& value, const Tail&...) {
+ return value;
+}
// Part of a compiled format string. It can be either literal text or a
// replacement field.
@@ -62,13 +88,15 @@ template struct part_counter {
if (begin != end) ++num_parts;
}
- FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
- FMT_CONSTEXPR void on_arg_id(int) { ++num_parts; }
- FMT_CONSTEXPR void on_arg_id(basic_string_view) { ++num_parts; }
+ FMT_CONSTEXPR int on_arg_id() { return ++num_parts, 0; }
+ FMT_CONSTEXPR int on_arg_id(int) { return ++num_parts, 0; }
+ FMT_CONSTEXPR int on_arg_id(basic_string_view) {
+ return ++num_parts, 0;
+ }
- FMT_CONSTEXPR void on_replacement_field(const Char*) {}
+ FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
- FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
+ FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
const Char* end) {
// Find the matching brace.
unsigned brace_counter = 0;
@@ -116,25 +144,28 @@ class format_string_compiler : public error_handler {
handler_(part::make_text({begin, to_unsigned(end - begin)}));
}
- FMT_CONSTEXPR void on_arg_id() {
+ FMT_CONSTEXPR int on_arg_id() {
part_ = part::make_arg_index(parse_context_.next_arg_id());
+ return 0;
}
- FMT_CONSTEXPR void on_arg_id(int id) {
+ FMT_CONSTEXPR int on_arg_id(int id) {
parse_context_.check_arg_id(id);
part_ = part::make_arg_index(id);
+ return 0;
}
- FMT_CONSTEXPR void on_arg_id(basic_string_view id) {
+ FMT_CONSTEXPR int on_arg_id(basic_string_view id) {
part_ = part::make_arg_name(id);
+ return 0;
}
- FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
+ FMT_CONSTEXPR void on_replacement_field(int, const Char* ptr) {
part_.arg_id_end = ptr;
handler_(part_);
}
- FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
+ FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
const Char* end) {
auto repl = typename part::replacement();
dynamic_specs_handler> handler(
@@ -160,23 +191,24 @@ FMT_CONSTEXPR void compile_format_string(basic_string_view format_str,
format_string_compiler(format_str, handler));
}
-template
+template
void format_arg(
- basic_format_parse_context& parse_ctx,
+ basic_format_parse_context& parse_ctx,
Context& ctx, Id arg_id) {
- ctx.advance_to(
- visit_format_arg(arg_formatter(ctx, &parse_ctx), ctx.arg(arg_id)));
+ ctx.advance_to(visit_format_arg(
+ arg_formatter(ctx, &parse_ctx),
+ ctx.arg(arg_id)));
}
// vformat_to is defined in a subnamespace to prevent ADL.
namespace cf {
-template
-auto vformat_to(Range out, CompiledFormat& cf, basic_format_args args)
- -> typename Context::iterator {
+template
+auto vformat_to(OutputIt out, CompiledFormat& cf,
+ basic_format_args args) -> typename Context::iterator {
using char_type = typename Context::char_type;
basic_format_parse_context parse_ctx(
to_string_view(cf.format_str_));
- Context ctx(out.begin(), args);
+ Context ctx(out, args);
const auto& parts = cf.parts();
for (auto part_it = std::begin(parts); part_it != std::end(parts);
@@ -197,12 +229,12 @@ auto vformat_to(Range out, CompiledFormat& cf, basic_format_args args)
case format_part_t::kind::arg_index:
advance_to(parse_ctx, part.arg_id_end);
- internal::format_arg(parse_ctx, ctx, value.arg_index);
+ detail::format_arg(parse_ctx, ctx, value.arg_index);
break;
case format_part_t::kind::arg_name:
advance_to(parse_ctx, part.arg_id_end);
- internal::format_arg(parse_ctx, ctx, value.str);
+ detail::format_arg(parse_ctx, ctx, value.str);
break;
case format_part_t::kind::replacement: {
@@ -226,7 +258,9 @@ auto vformat_to(Range out, CompiledFormat& cf, basic_format_args args)
advance_to(parse_ctx, part.arg_id_end);
ctx.advance_to(
- visit_format_arg(arg_formatter(ctx, nullptr, &specs), arg));
+ visit_format_arg(arg_formatter(
+ ctx, nullptr, &specs),
+ arg));
break;
}
}
@@ -240,7 +274,7 @@ struct basic_compiled_format {};
template
struct compiled_format_base : basic_compiled_format {
using char_type = char_t;
- using parts_container = std::vector>;
+ using parts_container = std::vector>;
parts_container compiled_parts;
@@ -305,7 +339,7 @@ struct compiled_format_base::value>>
const parts_container& parts() const {
static FMT_CONSTEXPR_DECL const auto compiled_parts =
compile_to_parts(
- internal::to_string_view(S()));
+ detail::to_string_view(S()));
return compiled_parts.data;
}
};
@@ -318,8 +352,8 @@ class compiled_format : private compiled_format_base {
private:
basic_string_view format_str_;
- template
- friend auto cf::vformat_to(Range out, CompiledFormat& cf,
+ template
+ friend auto cf::vformat_to(OutputIt out, CompiledFormat& cf,
basic_format_args args) ->
typename Context::iterator;
@@ -359,8 +393,7 @@ template struct text {
template
OutputIt format(OutputIt out, const Args&...) const {
- // TODO: reserve
- return copy_str(data.begin(), data.end(), out);
+ return write(out, data);
}
};
@@ -373,33 +406,6 @@ constexpr text make_text(basic_string_view s, size_t pos,
return {{&s[pos], size}};
}
-template , int> = 0>
-OutputIt format_default(OutputIt out, T value) {
- // TODO: reserve
- format_int fi(value);
- return std::copy(fi.data(), fi.data() + fi.size(), out);
-}
-
-template
-OutputIt format_default(OutputIt out, double value) {
- writer w(out);
- w.write(value);
- return w.out();
-}
-
-template
-OutputIt format_default(OutputIt out, Char value) {
- *out++ = value;
- return out;
-}
-
-template
-OutputIt format_default(OutputIt out, const Char* value) {
- auto length = std::char_traits::length(value);
- return copy_str(value, value + length, out);
-}
-
// A replacement field that refers to argument N.
template struct field {
using char_type = Char;
@@ -408,13 +414,30 @@ template struct field {
OutputIt format(OutputIt out, const Args&... args) const {
// This ensures that the argument type is convertile to `const T&`.
const T& arg = get(args...);
- return format_default(out, arg);
+ return write(out, arg);
}
};
template
struct is_compiled_format> : std::true_type {};
+// A replacement field that refers to argument N and has format specifiers.
+template struct spec_field {
+ using char_type = Char;
+ mutable formatter fmt;
+
+ template
+ OutputIt format(OutputIt out, const Args&... args) const {
+ // This ensures that the argument type is convertile to `const T&`.
+ const T& arg = get(args...);
+ basic_format_context ctx(out, {});
+ return fmt.format(arg, ctx);
+ }
+};
+
+template
+struct is_compiled_format> : std::true_type {};
+
template struct concat {
L lhs;
R rhs;
@@ -450,7 +473,8 @@ constexpr auto compile_format_string(S format_str);
template
constexpr auto parse_tail(T head, S format_str) {
- if constexpr (POS != to_string_view(format_str).size()) {
+ if constexpr (POS !=
+ basic_string_view(format_str).size()) {
constexpr auto tail = compile_format_string(format_str);
if constexpr (std::is_same,
unknown_format>())
@@ -462,6 +486,21 @@ constexpr auto parse_tail(T head, S format_str) {
}
}
+template struct parse_specs_result {
+ formatter fmt;
+ size_t end;
+};
+
+template
+constexpr parse_specs_result parse_specs(basic_string_view str,
+ size_t pos) {
+ str.remove_prefix(pos);
+ auto ctx = basic_format_parse_context(str);
+ auto f = formatter();
+ auto end = f.parse(ctx);
+ return {f, pos + (end - str.data()) + 1};
+}
+
// Compiles a non-empty format string and returns the compiled representation
// or unknown_format() on unrecognized input.
template
@@ -475,12 +514,13 @@ constexpr auto compile_format_string(S format_str) {
return parse_tail(make_text(str, POS, 1), format_str);
} else if constexpr (str[POS + 1] == '}') {
using type = get_type;
- if constexpr (std::is_same::value) {
- return parse_tail(field(),
- format_str);
- } else {
- return unknown_format();
- }
+ return parse_tail(field(),
+ format_str);
+ } else if constexpr (str[POS + 1] == ':') {
+ using type = get_type;
+ constexpr auto result = parse_specs(str, POS + 2);
+ return parse_tail(
+ spec_field{result.fmt}, format_str);
} else {
return unknown_format();
}
@@ -494,100 +534,130 @@ constexpr auto compile_format_string(S format_str) {
format_str);
}
}
-#endif // __cpp_if_constexpr
-} // namespace internal
-#if FMT_USE_CONSTEXPR
-# ifdef __cpp_if_constexpr
template ::value)>
+ FMT_ENABLE_IF(is_compile_string::value ||
+ detail::is_compiled_string::value)>
constexpr auto compile(S format_str) {
constexpr basic_string_view str = format_str;
if constexpr (str.size() == 0) {
- return internal::make_text(str, 0, 0);
+ return detail::make_text(str, 0, 0);
} else {
constexpr auto result =
- internal::compile_format_string, 0, 0>(
+ detail::compile_format_string, 0, 0>(
format_str);
if constexpr (std::is_same,
- internal::unknown_format>()) {
- return internal::compiled_format(to_string_view(format_str));
+ detail::unknown_format>()) {
+ return detail::compiled_format(to_string_view(format_str));
} else {
return result;
}
}
}
-
-template ::value)>
-std::basic_string format(const CompiledFormat& cf, const Args&... args) {
- basic_memory_buffer buffer;
- cf.format(std::back_inserter(buffer), args...);
- return to_string(buffer);
-}
-
-template ::value)>
-OutputIt format_to(OutputIt out, const CompiledFormat& cf,
- const Args&... args) {
- return cf.format(out, args...);
-}
-# else
+#else
template ::value)>
-constexpr auto compile(S format_str) -> internal::compiled_format {
- return internal::compiled_format(to_string_view(format_str));
+constexpr auto compile(S format_str) -> detail::compiled_format {
+ return detail::compiled_format(to_string_view(format_str));
}
-# endif // __cpp_if_constexpr
-#endif // FMT_USE_CONSTEXPR
+#endif // __cpp_if_constexpr
// Compiles the format string which must be a string literal.
template
auto compile(const Char (&format_str)[N])
- -> internal::compiled_format {
- return internal::compiled_format(
+ -> detail::compiled_format {
+ return detail::compiled_format(
basic_string_view(format_str, N - 1));
}
+} // namespace detail
+
+// DEPRECATED! use FMT_COMPILE instead.
+template
+FMT_DEPRECATED auto compile(const Args&... args)
+ -> decltype(detail::compile(args...)) {
+ return detail::compile(args...);
+}
+
+#if FMT_USE_CONSTEXPR
+# ifdef __cpp_if_constexpr
template ::value)>
-std::basic_string format(const CompiledFormat& cf, const Args&... args) {
+ FMT_ENABLE_IF(detail::is_compiled_format::value)>
+FMT_INLINE std::basic_string format(const CompiledFormat& cf,
+ const Args&... args) {
basic_memory_buffer buffer;
- using range = buffer_range;
- using context = buffer_context;
- internal::cf::vformat_to(range(buffer), cf,
- make_format_args(args...));
+ detail::buffer& base = buffer;
+ cf.format(std::back_inserter(base), args...);
return to_string(buffer);
}
template ::value)>
+OutputIt format_to(OutputIt out, const CompiledFormat& cf,
+ const Args&... args) {
+ return cf.format(out, args...);
+}
+# endif // __cpp_if_constexpr
+#endif // FMT_USE_CONSTEXPR
+
+template ::value)>
+std::basic_string format(const CompiledFormat& cf, const Args&... args) {
+ basic_memory_buffer buffer;
+ using context = buffer_context;
+ detail::buffer& base = buffer;
+ detail::cf::vformat_to(std::back_inserter(base), cf,
+ make_format_args(args...));
+ return to_string(buffer);
+}
+
+template ::value)>
+FMT_INLINE std::basic_string format(const S&,
+ Args&&... args) {
+ constexpr basic_string_view str = S();
+ if (str.size() == 2 && str[0] == '{' && str[1] == '}')
+ return fmt::to_string(detail::first(args...));
+ constexpr auto compiled = detail::compile