Compare commits
73 Commits
dev/migrie
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
795fdb043c | ||
|
|
82406c7886 | ||
|
|
d4b8b8bb6f | ||
|
|
1db0b70143 | ||
|
|
661fde5937 | ||
|
|
791e8c8d3c | ||
|
|
aead759d93 | ||
|
|
674c9182d7 | ||
|
|
4cee91f843 | ||
|
|
ad45139bb4 | ||
|
|
1721b91489 | ||
|
|
37c802c6df | ||
|
|
e7ff7903ac | ||
|
|
2db6967521 | ||
|
|
e8fff83307 | ||
|
|
e3ecc4d8da | ||
|
|
c38696da5d | ||
|
|
9e93ccbf32 | ||
|
|
16ce16e2f6 | ||
|
|
0d451cce2d | ||
|
|
c3b11bf827 | ||
|
|
45cde9edab | ||
|
|
3ac05363b1 | ||
|
|
14a7e45280 | ||
|
|
6aa3d70091 | ||
|
|
0284a917a6 | ||
|
|
f67db399c1 | ||
|
|
cddeb0898f | ||
|
|
bea3e7f696 | ||
|
|
fadd1852d3 | ||
|
|
15028f399e | ||
|
|
c00ae340db | ||
|
|
0c31c43cc4 | ||
|
|
806181db86 | ||
|
|
96930431c8 | ||
|
|
17f9dbf7bb | ||
|
|
aae9b83c42 | ||
|
|
e40b5e8ec1 | ||
|
|
842b162c85 | ||
|
|
a114d1b324 | ||
|
|
976a3c7d60 | ||
|
|
dd1c3df54d | ||
|
|
f8e8572c23 | ||
|
|
7b6625d7d9 | ||
|
|
a8aa295757 | ||
|
|
979ef5d981 | ||
|
|
0e68d0c09a | ||
|
|
823d28a8c6 | ||
|
|
aee33691bb | ||
|
|
3ca5374fe2 | ||
|
|
9e49ff2a05 | ||
|
|
3ffefeb39f | ||
|
|
80463833c1 | ||
|
|
396a698468 | ||
|
|
27bcdb03a2 | ||
|
|
a6af9a51ca | ||
|
|
1481475d2d | ||
|
|
2f81f5361c | ||
|
|
2d53cb2f4d | ||
|
|
42c01b83ea | ||
|
|
03b373f254 | ||
|
|
c7dc350504 | ||
|
|
7f1bdaf962 | ||
|
|
fb4dab0143 | ||
|
|
77f181febd | ||
|
|
89c9e6db84 | ||
|
|
f5f330a019 | ||
|
|
ec89b85462 | ||
|
|
e295cc4ae2 | ||
|
|
e103ca59e4 | ||
|
|
28c7890cbc | ||
|
|
4dee531aee | ||
|
|
c951a70208 |
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2021</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>8</VersionMinor>
|
||||
<VersionMinor>7</VersionMinor>
|
||||
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1137,6 +1137,11 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"tabColor": {
|
||||
"$ref": "#/definitions/Color",
|
||||
"description": "Sets the color of the profile's tab. Using the tab color picker will override this color.",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"tabTitle": {
|
||||
"description": "If set, will replace the name as the title to pass to the shell on startup. Some shells (like bash) may choose to ignore this initial value, while others (cmd, powershell) may use this value over the lifetime of the application.",
|
||||
"type": ["string", "null"]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "git",
|
||||
"git": {
|
||||
"repositoryUrl": "https://github.com/fmtlib/fmt",
|
||||
"commitHash": "f19b1a521ee8b606dedcadfda69fd10ddf882753"
|
||||
"commitHash": "7bdf0628b1276379886c7f6dda2cef2b3b374f0b"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,43 +72,27 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
||||
static_assert(F::is_integer, "From must be integral");
|
||||
static_assert(T::is_integer, "To must be integral");
|
||||
|
||||
if (F::is_signed && !T::is_signed) {
|
||||
if (detail::const_check(F::is_signed && !T::is_signed)) {
|
||||
// From may be negative, not allowed!
|
||||
if (fmt::detail::is_negative(from)) {
|
||||
ec = 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
// From is positive. Can it always fit in To?
|
||||
if (F::digits <= T::digits) {
|
||||
// yes, From always fits in To.
|
||||
} else {
|
||||
// from may not fit in To, we have to do a dynamic check
|
||||
if (from > static_cast<From>((T::max)())) {
|
||||
ec = 1;
|
||||
return {};
|
||||
}
|
||||
if (F::digits > T::digits &&
|
||||
from > static_cast<From>(detail::max_value<To>())) {
|
||||
ec = 1;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (!F::is_signed && T::is_signed) {
|
||||
// can from be held in To?
|
||||
if (F::digits < T::digits) {
|
||||
// yes, From always fits in To.
|
||||
} else {
|
||||
// from may not fit in To, we have to do a dynamic check
|
||||
if (from > static_cast<From>((T::max)())) {
|
||||
// outside range.
|
||||
ec = 1;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
if (!F::is_signed && T::is_signed && F::digits >= T::digits &&
|
||||
from > static_cast<From>(detail::max_value<To>())) {
|
||||
ec = 1;
|
||||
return {};
|
||||
}
|
||||
|
||||
// reaching here means all is ok for lossless conversion.
|
||||
return static_cast<To>(from);
|
||||
|
||||
} // function
|
||||
return static_cast<To>(from); // Lossless conversion.
|
||||
}
|
||||
|
||||
template <typename To, typename From,
|
||||
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
||||
@@ -190,11 +174,9 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||
// safe conversion to IntermediateRep
|
||||
IntermediateRep count =
|
||||
lossless_integral_conversion<IntermediateRep>(from.count(), ec);
|
||||
if (ec) {
|
||||
return {};
|
||||
}
|
||||
if (ec) return {};
|
||||
// multiply with Factor::num without overflow or underflow
|
||||
if (Factor::num != 1) {
|
||||
if (detail::const_check(Factor::num != 1)) {
|
||||
const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
|
||||
if (count > max1) {
|
||||
ec = 1;
|
||||
@@ -209,17 +191,9 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||
count *= Factor::num;
|
||||
}
|
||||
|
||||
// this can't go wrong, right? den>0 is checked earlier.
|
||||
if (Factor::den != 1) {
|
||||
count /= Factor::den;
|
||||
}
|
||||
// convert to the to type, safely
|
||||
using ToRep = typename To::rep;
|
||||
const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
|
||||
if (ec) {
|
||||
return {};
|
||||
}
|
||||
return To{tocount};
|
||||
if (detail::const_check(Factor::den != 1)) count /= Factor::den;
|
||||
auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
|
||||
return ec ? To() : To(tocount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,6 +325,11 @@ inline std::tm localtime(std::time_t time) {
|
||||
return lt.tm_;
|
||||
}
|
||||
|
||||
inline std::tm localtime(
|
||||
std::chrono::time_point<std::chrono::system_clock> time_point) {
|
||||
return localtime(std::chrono::system_clock::to_time_t(time_point));
|
||||
}
|
||||
|
||||
// Thread-safe replacement for std::gmtime
|
||||
inline std::tm gmtime(std::time_t time) {
|
||||
struct dispatcher {
|
||||
@@ -387,6 +366,11 @@ inline std::tm gmtime(std::time_t time) {
|
||||
return gt.tm_;
|
||||
}
|
||||
|
||||
inline std::tm gmtime(
|
||||
std::chrono::time_point<std::chrono::system_clock> time_point) {
|
||||
return gmtime(std::chrono::system_clock::to_time_t(time_point));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
inline size_t strftime(char* str, size_t count, const char* format,
|
||||
const std::tm* time) {
|
||||
@@ -399,6 +383,17 @@ inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::chrono::time_point<std::chrono::system_clock>, Char>
|
||||
: formatter<std::tm, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(std::chrono::time_point<std::chrono::system_clock> val,
|
||||
FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
std::tm time = localtime(val);
|
||||
return formatter<std::tm, Char>::format(time, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char> struct formatter<std::tm, Char> {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
|
||||
@@ -463,16 +463,16 @@ template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||
const char* begin = data::reset_color;
|
||||
const char* end = begin + sizeof(data::reset_color) - 1;
|
||||
buffer.append(begin, end);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
|
||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<Char>> args) {
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
bool has_style = false;
|
||||
if (ts.has_emphasis()) {
|
||||
has_style = true;
|
||||
@@ -496,7 +496,7 @@ void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||
basic_format_args<buffer_context<Char>> args) {
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
basic_memory_buffer<Char> buf;
|
||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
||||
buf.push_back(Char(0));
|
||||
@@ -504,20 +504,22 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats a string and prints it to the specified file stream using ANSI
|
||||
escape sequences to specify text formatting.
|
||||
Example:
|
||||
|
||||
**Example**::
|
||||
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||
const Args&... args) {
|
||||
detail::check_format_string<Args...>(format_str);
|
||||
using context = buffer_context<char_t<S>>;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
vprint(f, ts, format_str, basic_format_args<context>(as));
|
||||
vprint(f, ts, format_str,
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -558,7 +560,42 @@ template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||
const Args&... args) {
|
||||
return vformat(ts, to_string_view(format_str),
|
||||
detail::make_args_checked<Args...>(format_str, args...));
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
/**
|
||||
Formats a string with the given text_style and writes the output to ``out``.
|
||||
*/
|
||||
template <typename OutputIt, typename Char,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||
OutputIt vformat_to(
|
||||
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
|
||||
detail::vformat_to(buf, ts, format_str, args);
|
||||
return detail::get_iterator(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments with the given text_style, writes the result to the output
|
||||
iterator ``out`` and returns the iterator past the end of the output range.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::vector<char> out;
|
||||
fmt::format_to(std::back_inserter(out),
|
||||
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&&
|
||||
detail::is_string<S>::value>
|
||||
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
||||
Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
return vformat_to(out, ts, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
@@ -368,7 +368,8 @@ template <typename... Args> struct type_list {};
|
||||
|
||||
// Returns a reference to the argument at index N from [first, rest...].
|
||||
template <int N, typename T, typename... Args>
|
||||
constexpr const auto& get(const T& first, const Args&... rest) {
|
||||
constexpr const auto& get([[maybe_unused]] const T& first,
|
||||
[[maybe_unused]] const Args&... rest) {
|
||||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||
if constexpr (N == 0)
|
||||
return first;
|
||||
@@ -406,6 +407,19 @@ constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
||||
return {{&s[pos], size}};
|
||||
}
|
||||
|
||||
template <typename Char> struct code_unit {
|
||||
Char value;
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
OutputIt format(OutputIt out, const Args&...) const {
|
||||
return write<Char>(out, value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_compiled_format<code_unit<Char>> : std::true_type {};
|
||||
|
||||
// A replacement field that refers to argument N.
|
||||
template <typename Char, typename T, int N> struct field {
|
||||
using char_type = Char;
|
||||
@@ -430,7 +444,9 @@ template <typename Char, typename T, int N> struct spec_field {
|
||||
OutputIt format(OutputIt out, const Args&... args) const {
|
||||
// This ensures that the argument type is convertile to `const T&`.
|
||||
const T& arg = get<N>(args...);
|
||||
basic_format_context<OutputIt, Char> ctx(out, {});
|
||||
const auto& vargs =
|
||||
make_format_args<basic_format_context<OutputIt, Char>>(args...);
|
||||
basic_format_context<OutputIt, Char> ctx(out, vargs);
|
||||
return fmt.format(arg, ctx);
|
||||
}
|
||||
};
|
||||
@@ -489,16 +505,17 @@ constexpr auto parse_tail(T head, S format_str) {
|
||||
template <typename T, typename Char> struct parse_specs_result {
|
||||
formatter<T, Char> fmt;
|
||||
size_t end;
|
||||
int next_arg_id;
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||
size_t pos) {
|
||||
size_t pos, int arg_id) {
|
||||
str.remove_prefix(pos);
|
||||
auto ctx = basic_format_parse_context<Char>(str);
|
||||
auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
|
||||
auto f = formatter<T, Char>();
|
||||
auto end = f.parse(ctx);
|
||||
return {f, pos + (end - str.data()) + 1};
|
||||
return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
|
||||
}
|
||||
|
||||
// Compiles a non-empty format string and returns the compiled representation
|
||||
@@ -518,8 +535,8 @@ constexpr auto compile_format_string(S format_str) {
|
||||
format_str);
|
||||
} else if constexpr (str[POS + 1] == ':') {
|
||||
using type = get_type<ID, Args>;
|
||||
constexpr auto result = parse_specs<type>(str, POS + 2);
|
||||
return parse_tail<Args, result.end, ID + 1>(
|
||||
constexpr auto result = parse_specs<type>(str, POS + 2, ID);
|
||||
return parse_tail<Args, result.end, result.next_arg_id>(
|
||||
spec_field<char_type, type, ID>{result.fmt}, format_str);
|
||||
} else {
|
||||
return unknown_format();
|
||||
@@ -530,8 +547,13 @@ constexpr auto compile_format_string(S format_str) {
|
||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||
} else {
|
||||
constexpr auto end = parse_text(str, POS + 1);
|
||||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
||||
format_str);
|
||||
if constexpr (end - POS > 1) {
|
||||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
||||
format_str);
|
||||
} else {
|
||||
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
|
||||
format_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,8 +609,7 @@ template <typename CompiledFormat, typename... Args,
|
||||
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
detail::buffer<Char>& base = buffer;
|
||||
cf.format(std::back_inserter(base), args...);
|
||||
cf.format(detail::buffer_appender<Char>(buffer), args...);
|
||||
return to_string(buffer);
|
||||
}
|
||||
|
||||
@@ -608,8 +629,7 @@ template <typename CompiledFormat, typename... Args,
|
||||
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
using context = buffer_context<Char>;
|
||||
detail::buffer<Char>& base = buffer;
|
||||
detail::cf::vformat_to<context>(std::back_inserter(base), cf,
|
||||
detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf,
|
||||
make_format_args<context>(args...));
|
||||
return to_string(buffer);
|
||||
}
|
||||
@@ -618,9 +638,13 @@ template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
Args&&... args) {
|
||||
constexpr basic_string_view<typename S::char_type> str = S();
|
||||
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
|
||||
return fmt::to_string(detail::first(args...));
|
||||
#ifdef __cpp_if_constexpr
|
||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||
constexpr basic_string_view<typename S::char_type> str = S();
|
||||
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
|
||||
return fmt::to_string(detail::first(args...));
|
||||
}
|
||||
#endif
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
return format(compiled, std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -643,18 +667,30 @@ OutputIt format_to(OutputIt out, const S&, const Args&... args) {
|
||||
return format_to(out, compiled, args...);
|
||||
}
|
||||
|
||||
template <
|
||||
typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value&& std::is_base_of<
|
||||
detail::basic_compiled_format, CompiledFormat>::value)>
|
||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||
const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args>
|
||||
auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
|
||||
const Args&... args) ->
|
||||
typename std::enable_if<
|
||||
detail::is_output_iterator<OutputIt,
|
||||
typename CompiledFormat::char_type>::value &&
|
||||
std::is_base_of<detail::basic_compiled_format,
|
||||
CompiledFormat>::value,
|
||||
format_to_n_result<OutputIt>>::type {
|
||||
auto it =
|
||||
format_to(detail::truncating_iterator<OutputIt>(out, n), cf, args...);
|
||||
return {it.base(), it.count()};
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
|
||||
const Args&... args) {
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
|
||||
args...);
|
||||
return {it.base(), it.count()};
|
||||
}
|
||||
|
||||
template <typename CompiledFormat, typename... Args>
|
||||
size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
||||
return format_to(detail::counting_iterator(), cf, args...).count();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <vector>
|
||||
|
||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||
#define FMT_VERSION 70001
|
||||
#define FMT_VERSION 70103
|
||||
|
||||
#ifdef __clang__
|
||||
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
|
||||
@@ -57,6 +57,7 @@
|
||||
# define FMT_MSC_VER 0
|
||||
# define FMT_SUPPRESS_MSC_WARNING(n)
|
||||
#endif
|
||||
|
||||
#ifdef __has_feature
|
||||
# define FMT_HAS_FEATURE(x) __has_feature(x)
|
||||
#else
|
||||
@@ -64,7 +65,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(__has_include) && !defined(__INTELLISENSE__) && \
|
||||
!(FMT_ICC_VERSION && FMT_ICC_VERSION < 1600)
|
||||
(!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
|
||||
# define FMT_HAS_INCLUDE(x) __has_include(x)
|
||||
#else
|
||||
# define FMT_HAS_INCLUDE(x) 0
|
||||
@@ -99,7 +100,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef FMT_OVERRIDE
|
||||
# if FMT_HAS_FEATURE(cxx_override) || \
|
||||
# if FMT_HAS_FEATURE(cxx_override_control) || \
|
||||
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
|
||||
# define FMT_OVERRIDE override
|
||||
# else
|
||||
@@ -152,7 +153,7 @@
|
||||
# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
|
||||
# define FMT_DEPRECATED [[deprecated]]
|
||||
# else
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
|
||||
# define FMT_DEPRECATED __attribute__((deprecated))
|
||||
# elif FMT_MSC_VER
|
||||
# define FMT_DEPRECATED __declspec(deprecated)
|
||||
@@ -177,9 +178,17 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_BEGIN_NAMESPACE
|
||||
#ifndef FMT_USE_INLINE_NAMESPACES
|
||||
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
||||
FMT_MSC_VER >= 1900
|
||||
(FMT_MSC_VER >= 1900 && !_MANAGED)
|
||||
# define FMT_USE_INLINE_NAMESPACES 1
|
||||
# else
|
||||
# define FMT_USE_INLINE_NAMESPACES 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FMT_BEGIN_NAMESPACE
|
||||
# if FMT_USE_INLINE_NAMESPACES
|
||||
# define FMT_INLINE_NAMESPACE inline namespace
|
||||
# define FMT_END_NAMESPACE \
|
||||
} \
|
||||
@@ -269,8 +278,7 @@ struct monostate {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// A helper function to suppress bogus "conditional expression is constant"
|
||||
// warnings.
|
||||
// A helper function to suppress "conditional expression is constant" warnings.
|
||||
template <typename T> constexpr T const_check(T value) { return value; }
|
||||
|
||||
FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
|
||||
@@ -299,7 +307,8 @@ template <typename T> struct std_string_view {};
|
||||
|
||||
#ifdef FMT_USE_INT128
|
||||
// Do nothing.
|
||||
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
|
||||
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
|
||||
!(FMT_CLANG_VERSION && FMT_MSC_VER)
|
||||
# define FMT_USE_INT128 1
|
||||
using int128_t = __int128_t;
|
||||
using uint128_t = __uint128_t;
|
||||
@@ -506,6 +515,18 @@ template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
|
||||
using type = typename result::value_type;
|
||||
};
|
||||
|
||||
// Reports a compile-time error if S is not a valid format string.
|
||||
template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
|
||||
FMT_INLINE void check_format_string(const S&) {
|
||||
#ifdef FMT_ENFORCE_COMPILE_STRING
|
||||
static_assert(is_compile_string<S>::value,
|
||||
"FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
|
||||
"FMT_STRING.");
|
||||
#endif
|
||||
}
|
||||
template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||
void check_format_string(S);
|
||||
|
||||
struct error_handler {
|
||||
constexpr error_handler() = default;
|
||||
constexpr error_handler(const error_handler&) = default;
|
||||
@@ -545,8 +566,9 @@ class basic_format_parse_context : private ErrorHandler {
|
||||
using iterator = typename basic_string_view<Char>::iterator;
|
||||
|
||||
explicit constexpr basic_format_parse_context(
|
||||
basic_string_view<Char> format_str, ErrorHandler eh = {})
|
||||
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
|
||||
basic_string_view<Char> format_str, ErrorHandler eh = {},
|
||||
int next_arg_id = 0)
|
||||
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
|
||||
|
||||
/**
|
||||
Returns an iterator to the beginning of the format string range being
|
||||
@@ -616,8 +638,24 @@ template <typename T, typename Context>
|
||||
using has_formatter =
|
||||
std::is_constructible<typename Context::template formatter_type<T>>;
|
||||
|
||||
// Checks whether T is a container with contiguous storage.
|
||||
template <typename T> struct is_contiguous : std::false_type {};
|
||||
template <typename Char>
|
||||
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Extracts a reference to the container from back_insert_iterator.
|
||||
template <typename Container>
|
||||
inline Container& get_container(std::back_insert_iterator<Container> it) {
|
||||
using bi_iterator = std::back_insert_iterator<Container>;
|
||||
struct accessor : bi_iterator {
|
||||
accessor(bi_iterator iter) : bi_iterator(iter) {}
|
||||
using bi_iterator::container;
|
||||
};
|
||||
return *accessor(it).container;
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
A contiguous memory buffer with an optional growing ability. It is an internal
|
||||
@@ -640,6 +678,8 @@ template <typename T> class buffer {
|
||||
size_(sz),
|
||||
capacity_(cap) {}
|
||||
|
||||
~buffer() = default;
|
||||
|
||||
/** Sets the buffer data and capacity. */
|
||||
void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
|
||||
ptr_ = buf_data;
|
||||
@@ -655,7 +695,6 @@ template <typename T> class buffer {
|
||||
|
||||
buffer(const buffer&) = delete;
|
||||
void operator=(const buffer&) = delete;
|
||||
virtual ~buffer() = default;
|
||||
|
||||
T* begin() FMT_NOEXCEPT { return ptr_; }
|
||||
T* end() FMT_NOEXCEPT { return ptr_ + size_; }
|
||||
@@ -675,24 +714,26 @@ template <typename T> class buffer {
|
||||
/** Returns a pointer to the buffer data. */
|
||||
const T* data() const FMT_NOEXCEPT { return ptr_; }
|
||||
|
||||
/**
|
||||
Resizes the buffer. If T is a POD type new elements may not be initialized.
|
||||
*/
|
||||
void resize(size_t new_size) {
|
||||
reserve(new_size);
|
||||
size_ = new_size;
|
||||
}
|
||||
|
||||
/** Clears this buffer. */
|
||||
void clear() { size_ = 0; }
|
||||
|
||||
/** Reserves space to store at least *capacity* elements. */
|
||||
void reserve(size_t new_capacity) {
|
||||
// Tries resizing the buffer to contain *count* elements. If T is a POD type
|
||||
// the new elements may not be initialized.
|
||||
void try_resize(size_t count) {
|
||||
try_reserve(count);
|
||||
size_ = count <= capacity_ ? count : capacity_;
|
||||
}
|
||||
|
||||
// Tries increasing the buffer capacity to *new_capacity*. It can increase the
|
||||
// capacity by a smaller amount than requested but guarantees there is space
|
||||
// for at least one additional element either by increasing the capacity or by
|
||||
// flushing the buffer if it is full.
|
||||
void try_reserve(size_t new_capacity) {
|
||||
if (new_capacity > capacity_) grow(new_capacity);
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
reserve(size_ + 1);
|
||||
try_reserve(size_ + 1);
|
||||
ptr_[size_++] = value;
|
||||
}
|
||||
|
||||
@@ -705,32 +746,150 @@ template <typename T> class buffer {
|
||||
}
|
||||
};
|
||||
|
||||
// A container-backed buffer.
|
||||
struct buffer_traits {
|
||||
explicit buffer_traits(size_t) {}
|
||||
size_t count() const { return 0; }
|
||||
size_t limit(size_t size) { return size; }
|
||||
};
|
||||
|
||||
class fixed_buffer_traits {
|
||||
private:
|
||||
size_t count_ = 0;
|
||||
size_t limit_;
|
||||
|
||||
public:
|
||||
explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
|
||||
size_t count() const { return count_; }
|
||||
size_t limit(size_t size) {
|
||||
size_t n = limit_ > count_ ? limit_ - count_ : 0;
|
||||
count_ += size;
|
||||
return size < n ? size : n;
|
||||
}
|
||||
};
|
||||
|
||||
// A buffer that writes to an output iterator when flushed.
|
||||
template <typename OutputIt, typename T, typename Traits = buffer_traits>
|
||||
class iterator_buffer final : public Traits, public buffer<T> {
|
||||
private:
|
||||
OutputIt out_;
|
||||
enum { buffer_size = 256 };
|
||||
T data_[buffer_size];
|
||||
|
||||
protected:
|
||||
void grow(size_t) final FMT_OVERRIDE {
|
||||
if (this->size() == buffer_size) flush();
|
||||
}
|
||||
void flush();
|
||||
|
||||
public:
|
||||
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
|
||||
: Traits(n),
|
||||
buffer<T>(data_, 0, buffer_size),
|
||||
out_(out) {}
|
||||
~iterator_buffer() { flush(); }
|
||||
|
||||
OutputIt out() {
|
||||
flush();
|
||||
return out_;
|
||||
}
|
||||
size_t count() const { return Traits::count() + this->size(); }
|
||||
};
|
||||
|
||||
template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
|
||||
protected:
|
||||
void grow(size_t) final FMT_OVERRIDE {}
|
||||
|
||||
public:
|
||||
explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
|
||||
|
||||
T* out() { return &*this->end(); }
|
||||
};
|
||||
|
||||
// A buffer that writes to a container with the contiguous storage.
|
||||
template <typename Container>
|
||||
class container_buffer : public buffer<typename Container::value_type> {
|
||||
class iterator_buffer<std::back_insert_iterator<Container>,
|
||||
enable_if_t<is_contiguous<Container>::value,
|
||||
typename Container::value_type>>
|
||||
final : public buffer<typename Container::value_type> {
|
||||
private:
|
||||
Container& container_;
|
||||
|
||||
protected:
|
||||
void grow(size_t capacity) FMT_OVERRIDE {
|
||||
void grow(size_t capacity) final FMT_OVERRIDE {
|
||||
container_.resize(capacity);
|
||||
this->set(&container_[0], capacity);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit container_buffer(Container& c)
|
||||
explicit iterator_buffer(Container& c)
|
||||
: buffer<typename Container::value_type>(c.size()), container_(c) {}
|
||||
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
|
||||
: iterator_buffer(get_container(out)) {}
|
||||
std::back_insert_iterator<Container> out() {
|
||||
return std::back_inserter(container_);
|
||||
}
|
||||
};
|
||||
|
||||
// Extracts a reference to the container from back_insert_iterator.
|
||||
template <typename Container>
|
||||
inline Container& get_container(std::back_insert_iterator<Container> it) {
|
||||
using bi_iterator = std::back_insert_iterator<Container>;
|
||||
struct accessor : bi_iterator {
|
||||
accessor(bi_iterator iter) : bi_iterator(iter) {}
|
||||
using bi_iterator::container;
|
||||
};
|
||||
return *accessor(it).container;
|
||||
// A buffer that counts the number of code units written discarding the output.
|
||||
template <typename T = char> class counting_buffer final : public buffer<T> {
|
||||
private:
|
||||
enum { buffer_size = 256 };
|
||||
T data_[buffer_size];
|
||||
size_t count_ = 0;
|
||||
|
||||
protected:
|
||||
void grow(size_t) final FMT_OVERRIDE {
|
||||
if (this->size() != buffer_size) return;
|
||||
count_ += this->size();
|
||||
this->clear();
|
||||
}
|
||||
|
||||
public:
|
||||
counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
|
||||
|
||||
size_t count() { return count_ + this->size(); }
|
||||
};
|
||||
|
||||
// An output iterator that appends to the buffer.
|
||||
// It is used to reduce symbol sizes for the common case.
|
||||
template <typename T>
|
||||
class buffer_appender : public std::back_insert_iterator<buffer<T>> {
|
||||
using base = std::back_insert_iterator<buffer<T>>;
|
||||
|
||||
public:
|
||||
explicit buffer_appender(buffer<T>& buf) : base(buf) {}
|
||||
buffer_appender(base it) : base(it) {}
|
||||
|
||||
buffer_appender& operator++() {
|
||||
base::operator++();
|
||||
return *this;
|
||||
}
|
||||
|
||||
buffer_appender operator++(int) {
|
||||
buffer_appender tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
// Maps an output iterator into a buffer.
|
||||
template <typename T, typename OutputIt>
|
||||
iterator_buffer<OutputIt, T> get_buffer(OutputIt);
|
||||
template <typename T> buffer<T>& get_buffer(buffer_appender<T>);
|
||||
|
||||
template <typename OutputIt> OutputIt get_buffer_init(OutputIt out) {
|
||||
return out;
|
||||
}
|
||||
template <typename T> buffer<T>& get_buffer_init(buffer_appender<T> out) {
|
||||
return get_container(out);
|
||||
}
|
||||
|
||||
template <typename Buffer>
|
||||
auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
|
||||
return buf.out();
|
||||
}
|
||||
template <typename T> buffer_appender<T> get_iterator(buffer<T>& buf) {
|
||||
return buffer_appender<T>(buf);
|
||||
}
|
||||
|
||||
template <typename T, typename Char = char, typename Enable = void>
|
||||
@@ -759,7 +918,8 @@ template <typename Char> struct named_arg_info {
|
||||
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
|
||||
struct arg_data {
|
||||
// args_[0].named_args points to named_args_ to avoid bloating format_args.
|
||||
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : 1)];
|
||||
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
|
||||
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
|
||||
named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
|
||||
|
||||
template <typename... U>
|
||||
@@ -771,7 +931,8 @@ struct arg_data {
|
||||
|
||||
template <typename T, typename Char, size_t NUM_ARGS>
|
||||
struct arg_data<T, Char, NUM_ARGS, 0> {
|
||||
T args_[NUM_ARGS != 0 ? NUM_ARGS : 1];
|
||||
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
|
||||
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
|
||||
|
||||
template <typename... U>
|
||||
FMT_INLINE arg_data(const U&... init) : args_{init...} {}
|
||||
@@ -959,6 +1120,8 @@ enum { long_short = sizeof(long) == sizeof(int) };
|
||||
using long_type = conditional_t<long_short, int, long long>;
|
||||
using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
|
||||
|
||||
struct unformattable {};
|
||||
|
||||
// Maps formatting arguments to core types.
|
||||
template <typename Context> struct arg_mapper {
|
||||
using char_type = typename Context::char_type;
|
||||
@@ -1067,15 +1230,7 @@ template <typename Context> struct arg_mapper {
|
||||
return map(val.value);
|
||||
}
|
||||
|
||||
int map(...) {
|
||||
constexpr bool formattable = sizeof(Context) == 0;
|
||||
static_assert(
|
||||
formattable,
|
||||
"Cannot format argument. To make type T formattable provide a "
|
||||
"formatter<T> specialization: "
|
||||
"https://fmt.dev/latest/api.html#formatting-user-defined-types");
|
||||
return 0;
|
||||
}
|
||||
unformattable map(...) { return {}; }
|
||||
};
|
||||
|
||||
// A type constant after applying arg_mapper<Context>.
|
||||
@@ -1199,15 +1354,25 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
|
||||
return vis(monostate());
|
||||
}
|
||||
|
||||
// Checks whether T is a container with contiguous storage.
|
||||
template <typename T> struct is_contiguous : std::false_type {};
|
||||
template <typename Char>
|
||||
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
|
||||
template <typename Char>
|
||||
struct is_contiguous<detail::buffer<Char>> : std::true_type {};
|
||||
template <typename T> struct formattable : std::false_type {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
|
||||
template <typename... Ts> struct void_t_impl { using type = void; };
|
||||
template <typename... Ts>
|
||||
using void_t = typename detail::void_t_impl<Ts...>::type;
|
||||
|
||||
template <typename It, typename T, typename Enable = void>
|
||||
struct is_output_iterator : std::false_type {};
|
||||
|
||||
template <typename It, typename T>
|
||||
struct is_output_iterator<
|
||||
It, T,
|
||||
void_t<typename std::iterator_traits<It>::iterator_category,
|
||||
decltype(*std::declval<It>() = std::declval<T>())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename OutputIt>
|
||||
struct is_back_insert_iterator : std::false_type {};
|
||||
template <typename Container>
|
||||
@@ -1219,6 +1384,9 @@ struct is_contiguous_back_insert_iterator : std::false_type {};
|
||||
template <typename Container>
|
||||
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
|
||||
: is_contiguous<Container> {};
|
||||
template <typename Char>
|
||||
struct is_contiguous_back_insert_iterator<buffer_appender<Char>>
|
||||
: std::true_type {};
|
||||
|
||||
// A type-erased reference to an std::locale to avoid heavy <locale> include.
|
||||
class locale_ref {
|
||||
@@ -1250,13 +1418,24 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename T> int check(unformattable) {
|
||||
static_assert(
|
||||
formattable<T>(),
|
||||
"Cannot format an argument. To make type T formattable provide a "
|
||||
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
|
||||
return 0;
|
||||
}
|
||||
template <typename T, typename U> inline const U& check(const U& val) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// The type template parameter is there to avoid an ODR violation when using
|
||||
// a fallback formatter in one translation unit and an implicit conversion in
|
||||
// another (not recommended).
|
||||
template <bool IS_PACKED, typename Context, type, typename T,
|
||||
FMT_ENABLE_IF(IS_PACKED)>
|
||||
inline value<Context> make_arg(const T& val) {
|
||||
return arg_mapper<Context>().map(val);
|
||||
return check<T>(arg_mapper<Context>().map(val));
|
||||
}
|
||||
|
||||
template <bool IS_PACKED, typename Context, type, typename T,
|
||||
@@ -1356,13 +1535,13 @@ template <typename OutputIt, typename Char> class basic_format_context {
|
||||
|
||||
template <typename Char>
|
||||
using buffer_context =
|
||||
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>;
|
||||
basic_format_context<detail::buffer_appender<Char>, Char>;
|
||||
using format_context = buffer_context<char>;
|
||||
using wformat_context = buffer_context<wchar_t>;
|
||||
|
||||
// Workaround a bug in gcc: https://stackoverflow.com/q/62767544/471164.
|
||||
// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
|
||||
#define FMT_BUFFER_CONTEXT(Char) \
|
||||
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>
|
||||
basic_format_context<detail::buffer_appender<Char>, Char>
|
||||
|
||||
/**
|
||||
\rst
|
||||
@@ -1414,7 +1593,7 @@ class format_arg_store
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||
Constructs a `~fmt::format_arg_store` object that contains references to
|
||||
arguments and can be implicitly converted to `~fmt::format_args`. `Context`
|
||||
can be omitted in which case it defaults to `~fmt::context`.
|
||||
See `~fmt::arg` for lifetime considerations.
|
||||
@@ -1426,6 +1605,27 @@ inline format_arg_store<Context, Args...> make_format_args(
|
||||
return {args...};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs a `~fmt::format_arg_store` object that contains references
|
||||
to arguments and can be implicitly converted to `~fmt::format_args`.
|
||||
If ``format_str`` is a compile-time string then `make_args_checked` checks
|
||||
its validity at compile time.
|
||||
\endrst
|
||||
*/
|
||||
template <typename... Args, typename S, typename Char = char_t<S>>
|
||||
inline auto make_args_checked(const S& format_str,
|
||||
const remove_reference_t<Args>&... args)
|
||||
-> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
|
||||
static_assert(
|
||||
detail::count<(
|
||||
std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
|
||||
std::is_reference<Args>::value)...>() == 0,
|
||||
"passing views as lvalues is disallowed");
|
||||
detail::check_format_string<Args...>(format_str);
|
||||
return {args...};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Returns a named argument to be used in a formatting function. It should only
|
||||
@@ -1713,7 +1913,7 @@ template <typename Context> class basic_format_args {
|
||||
}
|
||||
|
||||
template <typename Char> int get_id(basic_string_view<Char> name) const {
|
||||
if (!has_named_args()) return {};
|
||||
if (!has_named_args()) return -1;
|
||||
const auto& named_args =
|
||||
(is_packed() ? values_[-1] : args_[-1].value_).named_args;
|
||||
for (size_t i = 0; i < named_args.size; ++i) {
|
||||
@@ -1729,7 +1929,14 @@ template <typename Context> class basic_format_args {
|
||||
}
|
||||
};
|
||||
|
||||
/** An alias to ``basic_format_args<context>``. */
|
||||
#ifdef FMT_ARM_ABI_COMPATIBILITY
|
||||
/** An alias to ``basic_format_args<format_context>``. */
|
||||
// Separate types would result in shorter symbols but break ABI compatibility
|
||||
// between clang and gcc on ARM (#1919).
|
||||
using format_args = basic_format_args<format_context>;
|
||||
using wformat_args = basic_format_args<wformat_context>;
|
||||
#else
|
||||
// DEPRECATED! These are kept for ABI compatibility.
|
||||
// It is a separate type rather than an alias to make symbols readable.
|
||||
struct format_args : basic_format_args<format_context> {
|
||||
template <typename... Args>
|
||||
@@ -1738,32 +1945,10 @@ struct format_args : basic_format_args<format_context> {
|
||||
struct wformat_args : basic_format_args<wformat_context> {
|
||||
using basic_format_args::basic_format_args;
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Reports a compile-time error if S is not a valid format string.
|
||||
template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
|
||||
FMT_INLINE void check_format_string(const S&) {
|
||||
#ifdef FMT_ENFORCE_COMPILE_STRING
|
||||
static_assert(is_compile_string<S>::value,
|
||||
"FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
|
||||
"FMT_STRING.");
|
||||
#endif
|
||||
}
|
||||
template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||
void check_format_string(S);
|
||||
|
||||
template <typename... Args, typename S, typename Char = char_t<S>>
|
||||
inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
|
||||
make_args_checked(const S& format_str,
|
||||
const remove_reference_t<Args>&... args) {
|
||||
static_assert(count<(std::is_base_of<view, remove_reference_t<Args>>::value &&
|
||||
std::is_reference<Args>::value)...>() == 0,
|
||||
"passing views as lvalues is disallowed");
|
||||
check_format_string<Args...>(format_str);
|
||||
return {args...};
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
std::basic_string<Char> vformat(
|
||||
basic_string_view<Char> format_str,
|
||||
@@ -1772,9 +1957,10 @@ std::basic_string<Char> vformat(
|
||||
FMT_API std::string vformat(string_view format_str, format_args args);
|
||||
|
||||
template <typename Char>
|
||||
typename FMT_BUFFER_CONTEXT(Char)::iterator vformat_to(
|
||||
void vformat_to(
|
||||
buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||
basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args);
|
||||
basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
|
||||
detail::locale_ref loc = {});
|
||||
|
||||
template <typename Char, typename Args,
|
||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
@@ -1789,26 +1975,80 @@ inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
|
||||
/** Formats a string and writes the output to ``out``. */
|
||||
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
|
||||
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
|
||||
template <
|
||||
typename OutputIt, typename S, typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_contiguous_back_insert_iterator<OutputIt>::value)>
|
||||
OutputIt vformat_to(
|
||||
OutputIt out, const S& format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
auto& c = detail::get_container(out);
|
||||
detail::container_buffer<remove_reference_t<decltype(c)>> buf(c);
|
||||
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||
bool enable = detail::is_output_iterator<OutputIt, Char>::value>
|
||||
auto vformat_to(OutputIt out, const S& format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||
-> typename std::enable_if<enable, OutputIt>::type {
|
||||
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
|
||||
detail::vformat_to(buf, to_string_view(format_str), args);
|
||||
return out;
|
||||
return detail::get_iterator(buf);
|
||||
}
|
||||
|
||||
template <typename Container, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(
|
||||
is_contiguous<Container>::value&& detail::is_string<S>::value)>
|
||||
inline std::back_insert_iterator<Container> format_to(
|
||||
std::back_insert_iterator<Container> out, const S& format_str,
|
||||
Args&&... args) {
|
||||
return vformat_to(out, to_string_view(format_str),
|
||||
detail::make_args_checked<Args...>(format_str, args...));
|
||||
/**
|
||||
\rst
|
||||
Formats arguments, writes the result to the output iterator ``out`` and returns
|
||||
the iterator past the end of the output range.
|
||||
|
||||
**Example**::
|
||||
|
||||
std::vector<char> out;
|
||||
fmt::format_to(std::back_inserter(out), "{}", 42);
|
||||
\endrst
|
||||
*/
|
||||
// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3.
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
||||
inline auto format_to(OutputIt out, const S& format_str, Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return vformat_to(out, to_string_view(format_str), vargs);
|
||||
}
|
||||
|
||||
template <typename OutputIt> struct format_to_n_result {
|
||||
/** Iterator past the end of the output range. */
|
||||
OutputIt out;
|
||||
/** Total (not truncated) output size. */
|
||||
size_t size;
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Char, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||
inline format_to_n_result<OutputIt> vformat_to_n(
|
||||
OutputIt out, size_t n, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
|
||||
n);
|
||||
detail::vformat_to(buf, format_str, args);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Formats arguments, writes up to ``n`` characters of the result to the output
|
||||
iterator ``out`` and returns the total output size and the iterator past the
|
||||
end of the output range.
|
||||
\endrst
|
||||
*/
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
||||
inline auto format_to_n(OutputIt out, size_t n, const S& format_str,
|
||||
const Args&... args) ->
|
||||
typename std::enable_if<enable, format_to_n_result<OutputIt>>::type {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return vformat_to_n(out, n, to_string_view(format_str), vargs);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of characters in the output of
|
||||
``format(format_str, args...)``.
|
||||
*/
|
||||
template <typename... Args>
|
||||
inline size_t formatted_size(string_view format_str, Args&&... args) {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
detail::counting_buffer<> buf;
|
||||
detail::vformat_to(buf, format_str, vargs);
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
template <typename S, typename Char = char_t<S>>
|
||||
@@ -1832,7 +2072,7 @@ FMT_INLINE std::basic_string<Char> vformat(
|
||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) {
|
||||
const auto& vargs = detail::make_args_checked<Args...>(format_str, args...);
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return detail::vformat(to_string_view(format_str), vargs);
|
||||
}
|
||||
|
||||
@@ -1852,7 +2092,7 @@ FMT_API void vprint(std::FILE*, string_view, format_args);
|
||||
*/
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline void print(std::FILE* f, const S& format_str, Args&&... args) {
|
||||
const auto& vargs = detail::make_args_checked<Args...>(format_str, args...);
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return detail::is_unicode<Char>()
|
||||
? vprint(f, to_string_view(format_str), vargs)
|
||||
: detail::vprint_mojibake(f, to_string_view(format_str), vargs);
|
||||
@@ -1871,7 +2111,7 @@ inline void print(std::FILE* f, const S& format_str, Args&&... args) {
|
||||
*/
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline void print(const S& format_str, Args&&... args) {
|
||||
const auto& vargs = detail::make_args_checked<Args...>(format_str, args...);
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return detail::is_unicode<Char>()
|
||||
? vprint(to_string_view(format_str), vargs)
|
||||
: detail::vprint_mojibake(stdout, to_string_view(format_str),
|
||||
|
||||
@@ -15,22 +15,12 @@
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
template <typename Char>
|
||||
typename buffer_context<Char>::iterator vformat_to(
|
||||
const std::locale& loc, buffer<Char>& buf,
|
||||
basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
using af = arg_formatter<typename buffer_context<Char>::iterator, Char>;
|
||||
return vformat_to<af>(std::back_inserter(buf), to_string_view(format_str),
|
||||
args, detail::locale_ref(loc));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
std::basic_string<Char> vformat(
|
||||
const std::locale& loc, basic_string_view<Char> format_str,
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
detail::vformat_to(loc, buffer, format_str, args);
|
||||
detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
|
||||
return fmt::to_string(buffer);
|
||||
}
|
||||
} // namespace detail
|
||||
@@ -45,32 +35,28 @@ inline std::basic_string<Char> vformat(
|
||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||
inline std::basic_string<Char> format(const std::locale& loc,
|
||||
const S& format_str, Args&&... args) {
|
||||
return detail::vformat(
|
||||
loc, to_string_view(format_str),
|
||||
detail::make_args_checked<Args...>(format_str, args...));
|
||||
return detail::vformat(loc, to_string_view(format_str),
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
|
||||
template <typename S, typename OutputIt, typename... Args,
|
||||
typename Char = enable_if_t<
|
||||
detail::is_output_iterator<OutputIt>::value, char_t<S>>>
|
||||
typename Char = char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||
inline OutputIt vformat_to(
|
||||
OutputIt out, const std::locale& loc, const S& format_str,
|
||||
format_args_t<type_identity_t<OutputIt>, Char> args) {
|
||||
using af = detail::arg_formatter<OutputIt, Char>;
|
||||
return vformat_to<af>(out, to_string_view(format_str), args,
|
||||
detail::locale_ref(loc));
|
||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
|
||||
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
||||
return detail::get_iterator(buf);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value&&
|
||||
detail::is_string<S>::value)>
|
||||
inline OutputIt format_to(OutputIt out, const std::locale& loc,
|
||||
const S& format_str, Args&&... args) {
|
||||
detail::check_format_string<Args...>(format_str);
|
||||
using context = format_context_t<OutputIt, char_t<S>>;
|
||||
format_arg_store<context, Args...> as{args...};
|
||||
return vformat_to(out, loc, to_string_view(format_str),
|
||||
basic_format_args<context>(as));
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
||||
inline auto format_to(OutputIt out, const std::locale& loc,
|
||||
const S& format_str, Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||
}
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
#if FMT_HAS_INCLUDE("winapifamily.h")
|
||||
# include <winapifamily.h>
|
||||
#endif
|
||||
#if FMT_HAS_INCLUDE("fcntl.h") && \
|
||||
#if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
# include <fcntl.h> // for O_RDONLY
|
||||
# define FMT_USE_FCNTL 1
|
||||
@@ -278,7 +279,8 @@ class file {
|
||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
||||
CREATE = FMT_POSIX(O_CREAT) // Create if the file doesn't exist.
|
||||
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
||||
APPEND = FMT_POSIX(O_APPEND) // Open in append mode.
|
||||
};
|
||||
|
||||
// Constructs a file object which doesn't represent any file.
|
||||
@@ -343,36 +345,69 @@ class file {
|
||||
// Returns the memory page size.
|
||||
long getpagesize();
|
||||
|
||||
class direct_buffered_file;
|
||||
namespace detail {
|
||||
|
||||
template <typename S, typename... Args>
|
||||
void print(direct_buffered_file& f, const S& format_str,
|
||||
const Args&... args);
|
||||
struct buffer_size {
|
||||
size_t value = 0;
|
||||
buffer_size operator=(size_t val) const {
|
||||
auto bs = buffer_size();
|
||||
bs.value = val;
|
||||
return bs;
|
||||
}
|
||||
};
|
||||
|
||||
// A buffered file with a direct buffer access and no synchronization.
|
||||
class direct_buffered_file {
|
||||
struct ostream_params {
|
||||
int oflag = file::WRONLY | file::CREATE;
|
||||
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
||||
|
||||
ostream_params() {}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, int oflag) : ostream_params(params...) {
|
||||
this->oflag = oflag;
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
ostream_params(T... params, detail::buffer_size bs)
|
||||
: ostream_params(params...) {
|
||||
this->buffer_size = bs.value;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
static constexpr detail::buffer_size buffer_size;
|
||||
|
||||
// A fast output stream which is not thread-safe.
|
||||
class ostream final : private detail::buffer<char> {
|
||||
private:
|
||||
file file_;
|
||||
|
||||
enum { buffer_size = 4096 };
|
||||
char buffer_[buffer_size];
|
||||
int pos_;
|
||||
|
||||
void flush() {
|
||||
if (pos_ == 0) return;
|
||||
file_.write(buffer_, pos_);
|
||||
pos_ = 0;
|
||||
if (size() == 0) return;
|
||||
file_.write(data(), size());
|
||||
clear();
|
||||
}
|
||||
|
||||
int free_capacity() const { return buffer_size - pos_; }
|
||||
FMT_API void grow(size_t) override final;
|
||||
|
||||
ostream(cstring_view path, const detail::ostream_params& params)
|
||||
: file_(path, params.oflag) {
|
||||
set(new char[params.buffer_size], params.buffer_size);
|
||||
}
|
||||
|
||||
public:
|
||||
direct_buffered_file(cstring_view path, int oflag)
|
||||
: file_(path, oflag), pos_(0) {}
|
||||
|
||||
~direct_buffered_file() {
|
||||
flush();
|
||||
ostream(ostream&& other)
|
||||
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
|
||||
file_(std::move(other.file_)) {
|
||||
other.set(nullptr, 0);
|
||||
}
|
||||
~ostream() {
|
||||
flush();
|
||||
delete[] data();
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
friend ostream output_file(cstring_view path, T... params);
|
||||
|
||||
void close() {
|
||||
flush();
|
||||
@@ -380,25 +415,20 @@ class direct_buffered_file {
|
||||
}
|
||||
|
||||
template <typename S, typename... Args>
|
||||
friend void print(direct_buffered_file& f, const S& format_str,
|
||||
const Args&... args) {
|
||||
// We could avoid double buffering.
|
||||
auto buf = fmt::memory_buffer();
|
||||
fmt::format_to(std::back_inserter(buf), format_str, args...);
|
||||
auto remaining_pos = 0;
|
||||
auto remaining_size = buf.size();
|
||||
while (remaining_size > detail::to_unsigned(f.free_capacity())) {
|
||||
auto size = f.free_capacity();
|
||||
memcpy(f.buffer_ + f.pos_, buf.data() + remaining_pos, size);
|
||||
f.pos_ += size;
|
||||
f.flush();
|
||||
remaining_pos += size;
|
||||
remaining_size -= size;
|
||||
}
|
||||
memcpy(f.buffer_ + f.pos_, buf.data() + remaining_pos, remaining_size);
|
||||
f.pos_ += static_cast<int>(remaining_size);
|
||||
void print(const S& format_str, const Args&... args) {
|
||||
format_to(detail::buffer_appender<char>(*this), format_str, args...);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Opens a file for writing. Supported parameters passed in `params`:
|
||||
* ``<integer>``: Output flags (``file::WRONLY | file::CREATE`` by default)
|
||||
* ``buffer_size=<integer>``: Output buffer size
|
||||
*/
|
||||
template <typename... T>
|
||||
inline ostream output_file(cstring_view path, T... params) {
|
||||
return {path, detail::ostream_params(params...)};
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
|
||||
#ifdef FMT_LOCALE
|
||||
|
||||
@@ -49,17 +49,27 @@ template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||
}
|
||||
};
|
||||
|
||||
struct converter {
|
||||
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
|
||||
};
|
||||
|
||||
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||
private:
|
||||
// Hide all operator<< from std::basic_ostream<Char>.
|
||||
void_t<> operator<<(null<>);
|
||||
void_t<> operator<<(const Char*);
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
|
||||
!std::is_enum<T>::value)>
|
||||
void_t<> operator<<(T);
|
||||
void_t<> operator<<(converter);
|
||||
};
|
||||
|
||||
// Hide insertion operators for built-in types.
|
||||
template <typename Char, typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char);
|
||||
template <typename Char, typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<Char, Traits>&, char);
|
||||
template <typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<char, Traits>&, char);
|
||||
template <typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char);
|
||||
template <typename Traits>
|
||||
void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char);
|
||||
|
||||
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||
// std::ostream).
|
||||
template <typename T, typename Char> class is_streamable {
|
||||
@@ -103,7 +113,7 @@ void format_value(buffer<Char>& buf, const T& value,
|
||||
#endif
|
||||
output << value;
|
||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
buf.resize(buf.size());
|
||||
buf.try_resize(buf.size());
|
||||
}
|
||||
|
||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||
@@ -160,7 +170,7 @@ template <typename S, typename... Args,
|
||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||
vprint(os, to_string_view(format_str),
|
||||
detail::make_args_checked<Args...>(format_str, args...));
|
||||
fmt::make_args_checked<Args...>(format_str, args...));
|
||||
}
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ template <typename Char> class printf_width_handler {
|
||||
template <typename Char, typename Context>
|
||||
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
basic_format_args<Context> args) {
|
||||
Context(std::back_inserter(buf), format, args).format();
|
||||
Context(buffer_appender<Char>(buf), format, args).format();
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
@@ -598,7 +598,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||
|
||||
template <typename Char>
|
||||
using basic_printf_context_t =
|
||||
basic_printf_context<std::back_insert_iterator<detail::buffer<Char>>, Char>;
|
||||
basic_printf_context<detail::buffer_appender<Char>, Char>;
|
||||
|
||||
using printf_context = basic_printf_context_t<char>;
|
||||
using wprintf_context = basic_printf_context_t<wchar_t>;
|
||||
|
||||
@@ -157,6 +157,9 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
using value_type = remove_cvref_t<decltype(*std::declval<Range>().begin())>;
|
||||
|
||||
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
|
||||
typename std::decay<Arg>::type>::value)>
|
||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
||||
@@ -182,7 +185,6 @@ FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
||||
return add_space ? L" '{}'" : L"'{}'";
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_tuple_like {
|
||||
@@ -246,9 +248,18 @@ template <typename T, typename Char> struct is_range {
|
||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||
};
|
||||
|
||||
template <typename RangeT, typename Char>
|
||||
struct formatter<RangeT, Char,
|
||||
enable_if_t<fmt::is_range<RangeT, Char>::value>> {
|
||||
template <typename T, typename Char>
|
||||
struct formatter<
|
||||
T, Char,
|
||||
enable_if_t<fmt::is_range<T, Char>::value
|
||||
// Workaround a bug in MSVC 2017 and earlier.
|
||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
||||
&&
|
||||
(has_formatter<detail::value_type<T>, format_context>::value ||
|
||||
detail::has_fallback_formatter<detail::value_type<T>,
|
||||
format_context>::value)
|
||||
#endif
|
||||
>> {
|
||||
formatting_range<Char> formatting;
|
||||
|
||||
template <typename ParseContext>
|
||||
@@ -257,8 +268,7 @@ struct formatter<RangeT, Char,
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
typename FormatContext::iterator format(const RangeT& values,
|
||||
FormatContext& ctx) {
|
||||
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
|
||||
auto out = detail::copy(formatting.prefix, ctx.out());
|
||||
size_t i = 0;
|
||||
auto it = values.begin();
|
||||
|
||||
@@ -23,6 +23,36 @@ int format_float(char* buf, std::size_t size, const char* format, int precision,
|
||||
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
||||
: snprintf_ptr(buf, size, format, precision, value);
|
||||
}
|
||||
|
||||
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
|
||||
FMT_NOEXCEPT;
|
||||
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
|
||||
FMT_NOEXCEPT;
|
||||
|
||||
// DEPRECATED! This function exists for ABI compatibility.
|
||||
template <typename Char>
|
||||
typename basic_format_context<std::back_insert_iterator<buffer<Char>>,
|
||||
Char>::iterator
|
||||
vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||
basic_format_args<basic_format_context<
|
||||
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||
type_identity_t<Char>>>
|
||||
args) {
|
||||
using iterator = std::back_insert_iterator<buffer<char>>;
|
||||
using context = basic_format_context<
|
||||
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
|
||||
type_identity_t<Char>>;
|
||||
auto out = iterator(buf);
|
||||
format_handler<iterator, Char, context> h(out, format_str, args, {});
|
||||
parse_format_string<false>(format_str, h);
|
||||
return out;
|
||||
}
|
||||
template basic_format_context<std::back_insert_iterator<buffer<char>>,
|
||||
char>::iterator
|
||||
vformat_to(buffer<char>&, string_view,
|
||||
basic_format_args<basic_format_context<
|
||||
std::back_insert_iterator<buffer<type_identity_t<char>>>,
|
||||
type_identity_t<char>>>);
|
||||
} // namespace detail
|
||||
|
||||
template struct FMT_INSTANTIATION_DEF_API detail::basic_data<void>;
|
||||
@@ -44,9 +74,9 @@ template FMT_API char detail::decimal_point_impl(locale_ref);
|
||||
|
||||
template FMT_API void detail::buffer<char>::append(const char*, const char*);
|
||||
|
||||
template FMT_API FMT_BUFFER_CONTEXT(char)::iterator detail::vformat_to(
|
||||
template FMT_API void detail::vformat_to(
|
||||
detail::buffer<char>&, string_view,
|
||||
basic_format_args<FMT_BUFFER_CONTEXT(char)>);
|
||||
basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
|
||||
|
||||
template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
|
||||
detail::buffer<char>&);
|
||||
|
||||
@@ -62,7 +62,7 @@ using RWResult = int;
|
||||
inline unsigned convert_rwcount(std::size_t count) {
|
||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||
}
|
||||
#else
|
||||
#elif FMT_USE_FCNTL
|
||||
// Return type of read and write functions.
|
||||
using RWResult = ssize_t;
|
||||
|
||||
@@ -124,7 +124,8 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||
if (result != 0) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
format_to(std::back_inserter(out), "{}: {}", message, utf8_message);
|
||||
format_to(buffer_appender<char>(out), "{}: {}", message,
|
||||
utf8_message);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -288,12 +289,12 @@ void file::pipe(file& read_end, file& write_end) {
|
||||
}
|
||||
|
||||
buffered_file file::fdopen(const char* mode) {
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
#if defined(__MINGW32__) && defined(_POSIX_)
|
||||
// Don't retry as fdopen doesn't return EINTR.
|
||||
# if defined(__MINGW32__) && defined(_POSIX_)
|
||||
FILE* f = ::fdopen(fd_, mode);
|
||||
#else
|
||||
# else
|
||||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||
#endif
|
||||
# endif
|
||||
if (!f)
|
||||
FMT_THROW(
|
||||
system_error(errno, "cannot associate stream with file descriptor"));
|
||||
@@ -313,5 +314,9 @@ long getpagesize() {
|
||||
return size;
|
||||
# endif
|
||||
}
|
||||
|
||||
FMT_API void ostream::grow(size_t) {
|
||||
if (this->size() == this->capacity()) flush();
|
||||
}
|
||||
#endif // FMT_USE_FCNTL
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
1745
patch.diff
BIN
res/Cascadia.ttf
@@ -17,5 +17,5 @@ Please consult the [license](https://raw.githubusercontent.com/microsoft/cascadi
|
||||
|
||||
### Fonts Included
|
||||
|
||||
* Cascadia Code, Cascadia Mono (2102.03)
|
||||
* from microsoft/cascadia-code@b358d1ba3d1629c113671312b18eab52797cc055
|
||||
* Cascadia Code, Cascadia Mono (2102.25)
|
||||
* from microsoft/cascadia-code@911dc421f333e3b72b97381d16fee5b71eb48f04
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB |
@@ -43,6 +43,7 @@
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Server" Name="1A541C01-589A-496E-85A7-A9E02170166D"/>
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.VirtualTerminal.Parser" Name="c9ba2a84-d3ca-5e19-2bd6-776a0910cb9d"/>
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.Render.VtEngine" Name="c9ba2a95-d3ca-5e19-2bd6-776a0910cb9d"/>
|
||||
<EventProvider Id="EventProvider-Microsoft.Windows.Console.UIA" Name="e7ebce59-2161-572d-b263-2f16a6afb9e5"/>
|
||||
<!-- Now define some profiles. We'll call them by ID when collecting. Also, the Base is where it is inheriting from and is a .wprpi file built... -->
|
||||
<!-- ... into WPR automatically. Go look in the WPR install directory or in the documentation to find it. -->
|
||||
<Profile Id="ConsolePerfProfile.Verbose.File" Base="GeneralProfile.Light.File" LoggingMode="File" Name="ConsolePerfProfile" DetailLevel="Verbose" Description="Console Performance default profile">
|
||||
@@ -66,6 +67,7 @@
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Server"/>
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.VirtualTerminal.Parser"/>
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.Render.VtEngine"/>
|
||||
<EventProviderId Value="EventProvider-Microsoft.Windows.Console.UIA"/>
|
||||
</EventProviders>
|
||||
</EventCollectorId>
|
||||
</Collectors>
|
||||
|
||||
@@ -281,9 +281,9 @@ bool TextBuffer::_AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribut
|
||||
// - false otherwise (out of memory)
|
||||
bool TextBuffer::_PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute)
|
||||
{
|
||||
// Assert the buffer state is ready for this character
|
||||
// This function corrects most errors. If this is false, we had an uncorrectable one.
|
||||
FAIL_FAST_IF(!(_AssertValidDoubleByteSequence(dbcsAttribute))); // Shouldn't be uncorrectable sequences unless something is very wrong.
|
||||
// This function corrects most errors. If this is false, we had an uncorrectable one which
|
||||
// older versions of conhost simply let pass by unflinching.
|
||||
LOG_HR_IF(E_NOT_VALID_STATE, !(_AssertValidDoubleByteSequence(dbcsAttribute))); // Shouldn't be uncorrectable sequences unless something is very wrong.
|
||||
|
||||
bool fSuccess = true;
|
||||
// Now compensate if we don't have enough space for the upcoming double byte sequence
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png"/>
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
@@ -78,17 +77,17 @@
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
|
||||
<com:Class Id="9f156763-7844-4dc4-b2b1-901f640f5155" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
|
||||
<com:Class Id="52065414-e077-47ec-a3ac-1cc5455e1b54" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
|
||||
</com:SurrogateServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||
<desktop4:FileExplorerContextMenus>
|
||||
<desktop5:ItemType Type="Directory">
|
||||
<desktop5:Verb Id="Command1" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
<desktop5:Verb Id="OpenTerminalDev" Clsid="52065414-e077-47ec-a3ac-1cc5455e1b54" />
|
||||
</desktop5:ItemType>
|
||||
<desktop5:ItemType Type="Directory\Background">
|
||||
<desktop5:Verb Id="Command2" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
<desktop5:Verb Id="OpenTerminalDev" Clsid="52065414-e077-47ec-a3ac-1cc5455e1b54" />
|
||||
</desktop5:ItemType>
|
||||
</desktop4:FileExplorerContextMenus>
|
||||
</desktop4:Extension>
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png"/>
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
@@ -78,17 +77,17 @@
|
||||
<com:Extension Category="windows.comServer">
|
||||
<com:ComServer>
|
||||
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
|
||||
<com:Class Id="9f156763-7844-4dc4-b2b1-901f640f5155" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
|
||||
<com:Class Id="02db545a-3e20-46de-83a5-1329b1e88b6b" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
|
||||
</com:SurrogateServer>
|
||||
</com:ComServer>
|
||||
</com:Extension>
|
||||
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||
<desktop4:FileExplorerContextMenus>
|
||||
<desktop5:ItemType Type="Directory">
|
||||
<desktop5:Verb Id="Command1" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
<desktop5:Verb Id="OpenTerminalPre" Clsid="02db545a-3e20-46de-83a5-1329b1e88b6b" />
|
||||
</desktop5:ItemType>
|
||||
<desktop5:ItemType Type="Directory\Background">
|
||||
<desktop5:Verb Id="Command2" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
<desktop5:Verb Id="OpenTerminalPre" Clsid="02db545a-3e20-46de-83a5-1329b1e88b6b" />
|
||||
</desktop5:ItemType>
|
||||
</desktop4:FileExplorerContextMenus>
|
||||
</desktop4:Extension>
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
<uap:ShowOn Tile="square310x310Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png"/>
|
||||
</uap:VisualElements>
|
||||
|
||||
<Extensions>
|
||||
@@ -86,10 +85,10 @@
|
||||
<desktop4:Extension Category="windows.fileExplorerContextMenus">
|
||||
<desktop4:FileExplorerContextMenus>
|
||||
<desktop5:ItemType Type="Directory">
|
||||
<desktop5:Verb Id="Command1" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
<desktop5:Verb Id="OpenTerminalHere" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
</desktop5:ItemType>
|
||||
<desktop5:ItemType Type="Directory\Background">
|
||||
<desktop5:Verb Id="Command2" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
<desktop5:Verb Id="OpenTerminalHere" Clsid="9f156763-7844-4dc4-b2b1-901f640f5155" />
|
||||
</desktop5:ItemType>
|
||||
</desktop4:FileExplorerContextMenus>
|
||||
</desktop4:Extension>
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace SettingsModelLocalTests
|
||||
TEST_METHOD(TestCommandsAndKeybindings);
|
||||
|
||||
TEST_METHOD(TestNestedCommandWithoutName);
|
||||
TEST_METHOD(TestNestedCommandWithBadSubCommands);
|
||||
TEST_METHOD(TestUnbindNestedCommand);
|
||||
TEST_METHOD(TestRebindNestedCommand);
|
||||
|
||||
@@ -1376,7 +1377,7 @@ namespace SettingsModelLocalTests
|
||||
},
|
||||
{
|
||||
"name": "parent",
|
||||
"commands": [
|
||||
"commands": [
|
||||
{ "command": { "action": "setColorScheme", "colorScheme": "invalidScheme" } }
|
||||
]
|
||||
}
|
||||
@@ -1403,11 +1404,11 @@ namespace SettingsModelLocalTests
|
||||
},
|
||||
{
|
||||
"name": "grandparent",
|
||||
"commands": [
|
||||
"commands": [
|
||||
{
|
||||
"name": "parent",
|
||||
"commands": [
|
||||
{
|
||||
{
|
||||
"command": { "action": "setColorScheme", "colorScheme": "invalidScheme" }
|
||||
}
|
||||
]
|
||||
@@ -1909,7 +1910,8 @@ namespace SettingsModelLocalTests
|
||||
"keybindings": [
|
||||
{ "command": { "action": "splitPane", "split":"auto" }, "keys": [ "ctrl+alt+t", "ctrl+a" ] },
|
||||
{ "command": { "action": "moveFocus" }, "keys": [ "ctrl+a" ] },
|
||||
{ "command": { "action": "resizePane" }, "keys": [ "ctrl+b" ] }
|
||||
{ "command": { "action": "resizePane" }, "keys": [ "ctrl+b" ] },
|
||||
{ "name": "invalid nested", "commands":[ { "name" : "hello" }, { "name" : "world" } ] }
|
||||
]
|
||||
})" };
|
||||
|
||||
@@ -1918,18 +1920,20 @@ namespace SettingsModelLocalTests
|
||||
|
||||
VERIFY_ARE_EQUAL(0u, settings->_globals->_keymap->_keyShortcuts.size());
|
||||
|
||||
VERIFY_ARE_EQUAL(3u, settings->_globals->_keybindingsWarnings.size());
|
||||
VERIFY_ARE_EQUAL(4u, settings->_globals->_keybindingsWarnings.size());
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::TooManyKeysForChord, settings->_globals->_keybindingsWarnings.at(0));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(1));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_globals->_keybindingsWarnings.at(2));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::FailedToParseSubCommands, settings->_globals->_keybindingsWarnings.at(3));
|
||||
|
||||
settings->_ValidateKeybindings();
|
||||
|
||||
VERIFY_ARE_EQUAL(4u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(5u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::TooManyKeysForChord, settings->_warnings.GetAt(1));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(2));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->_warnings.GetAt(3));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::FailedToParseSubCommands, settings->_warnings.GetAt(4));
|
||||
}
|
||||
|
||||
void DeserializationTests::ValidateExecuteCommandlineWarning()
|
||||
@@ -2316,6 +2320,53 @@ namespace SettingsModelLocalTests
|
||||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||
}
|
||||
|
||||
void DeserializationTests::TestNestedCommandWithBadSubCommands()
|
||||
{
|
||||
// This test tests a nested command without a name specified. This type
|
||||
// of command should just be ignored, since we can't auto-generate names
|
||||
// for nested commands, they _must_ have names specified.
|
||||
|
||||
const std::string settingsJson{ R"(
|
||||
{
|
||||
"defaultProfile": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "profile0",
|
||||
"guid": "{6239a42c-0000-49a3-80bd-e8fdd045185c}",
|
||||
"historySize": 1,
|
||||
"commandline": "cmd.exe"
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"name": "nested command",
|
||||
"commands": [
|
||||
{
|
||||
"name": "child1"
|
||||
},
|
||||
{
|
||||
"name": "child2"
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
"schemes": [ { "name": "Campbell" } ] // This is included here to prevent settings validation errors.
|
||||
})" };
|
||||
|
||||
VerifyParseSucceeded(settingsJson);
|
||||
|
||||
auto settings = winrt::make_self<implementation::CascadiaSettings>();
|
||||
settings->_ParseJsonString(settingsJson, false);
|
||||
settings->LayerJson(settings->_userSettings);
|
||||
auto commands = settings->_globals->Commands();
|
||||
settings->_ValidateSettings();
|
||||
|
||||
VERIFY_ARE_EQUAL(2u, settings->_warnings.Size());
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::AtLeastOneKeybindingWarning, settings->_warnings.GetAt(0));
|
||||
VERIFY_ARE_EQUAL(SettingsLoadWarnings::FailedToParseSubCommands, settings->_warnings.GetAt(1));
|
||||
VERIFY_ARE_EQUAL(0u, commands.Size());
|
||||
}
|
||||
|
||||
void DeserializationTests::TestUnbindNestedCommand()
|
||||
{
|
||||
// Test that layering a command with `"commands": null` set will unbind a command that already exists.
|
||||
|
||||
@@ -1595,129 +1595,58 @@ namespace TerminalAppLocalTests
|
||||
{
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseAnyExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseAnyExisting,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"-1" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"new" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"-12345" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"12345" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(12345, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(12345, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(12345, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"0" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseCurrent, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseCurrent,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseCurrent, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseCurrent,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseCurrent, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"last" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseCurrent,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"new-tab" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseExisting,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseAnyExisting, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
}
|
||||
{
|
||||
std::vector<winrt::hstring> args{ L"wt.exe", L"-w", L"new-tab" };
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseName, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"new-tab", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseName, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"new-tab", result.WindowName());
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseName, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"new-tab", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseAnyExisting,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1728,23 +1657,19 @@ namespace TerminalAppLocalTests
|
||||
// This is a little helper to make sure that these args _always_ return
|
||||
// UseNew, regardless of the windowing behavior.
|
||||
auto testHelper = [](auto&& args) {
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
};
|
||||
|
||||
testHelper(std::vector<winrt::hstring>{ L"wt.exe", L"--help" });
|
||||
testHelper(std::vector<winrt::hstring>{ L"wt.exe", L"new-tab", L"--help" });
|
||||
testHelper(std::vector<winrt::hstring>{ L"wt.exe", L"-w", L"0", L"new-tab", L"--help" });
|
||||
testHelper(std::vector<winrt::hstring>{ L"wt.exe", L"-w", L"foo", L"new-tab", L"--help" });
|
||||
testHelper(std::vector<winrt::hstring>{ L"wt.exe", L"new-tab", L";", L"--help" });
|
||||
}
|
||||
|
||||
@@ -1755,17 +1680,14 @@ namespace TerminalAppLocalTests
|
||||
// This is a little helper to make sure that these args _always_ return
|
||||
// UseNew, regardless of the windowing behavior.
|
||||
auto testHelper = [](auto&& args) {
|
||||
auto result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseNew));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseExisting));
|
||||
|
||||
result = appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting);
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew, result.WindowId());
|
||||
VERIFY_ARE_EQUAL(L"", result.WindowName());
|
||||
VERIFY_ARE_EQUAL(WindowingBehaviorUseNew,
|
||||
appImpl::AppLogic::_doFindTargetWindow({ args }, WindowingMode::UseAnyExisting));
|
||||
};
|
||||
|
||||
testHelper(std::vector<winrt::hstring>{ L"wt.exe", L"--version" });
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
GETSET_PROPERTY(winrt::Microsoft::Terminal::Remoting::CommandlineArgs, Args, nullptr);
|
||||
GETSET_PROPERTY(int, ResultTargetWindow, -1);
|
||||
GETSET_PROPERTY(winrt::hstring, ResultTargetWindowName, L"");
|
||||
|
||||
public:
|
||||
FindTargetWindowArgs(winrt::Microsoft::Terminal::Remoting::CommandlineArgs args) :
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
<ClInclude Include="ProposeCommandlineResult.h">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RenameRequestArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowActivatedArgs.h">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
@@ -54,9 +51,6 @@
|
||||
<ClCompile Include="ProposeCommandlineResult.cpp">
|
||||
<DependentUpon>Monarch.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RenameRequestArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowActivatedArgs.cpp">
|
||||
<DependentUpon>Peasant.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
|
||||
@@ -75,8 +75,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
auto newPeasantsId = peasant.GetID();
|
||||
// Add an event listener to the peasant's WindowActivated event.
|
||||
peasant.WindowActivated({ this, &Monarch::_peasantWindowActivated });
|
||||
peasant.IdentifyWindowsRequested({ this, &Monarch::_identifyWindows });
|
||||
peasant.RenameRequested({ this, &Monarch::_renameRequested });
|
||||
|
||||
_peasants[newPeasantsId] = peasant;
|
||||
|
||||
@@ -149,56 +147,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Monarch::_lookupPeasantIdForName(const winrt::hstring& name)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> peasantsToErase{};
|
||||
uint64_t result = 0;
|
||||
for (const auto& [id, p] : _peasants)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto otherName = p.WindowName();
|
||||
if (otherName == name)
|
||||
{
|
||||
result = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
// Normally, we'd just erase the peasant here. However, we can't
|
||||
// erase from the map while we're iterating over it like this.
|
||||
// Instead, pull a good ole Java and collect this id for removal
|
||||
// later.
|
||||
peasantsToErase.push_back(id);
|
||||
|
||||
// // Remove the peasant from the list of peasants
|
||||
// _peasants.erase(id);
|
||||
// // Remove the peasant from the list of MRU windows. They're dead.
|
||||
// // They can't be the MRU anymore.
|
||||
// _clearOldMruEntries(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the dead peasants we came across while iterating.
|
||||
for (const auto& id : peasantsToErase)
|
||||
{
|
||||
// Remove the peasant from the list of peasants
|
||||
_peasants.erase(id);
|
||||
// Remove the peasant from the list of MRU windows. They're dead.
|
||||
// They can't be the MRU anymore.
|
||||
_clearOldMruEntries(id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handler for the `Peasant::WindowActivated` event. We'll make a in-proc
|
||||
// copy of the WindowActivatedArgs from the peasant. That way, we won't
|
||||
@@ -452,7 +400,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// After the event was handled, ResultTargetWindow() will be filled with
|
||||
// the parsed result.
|
||||
const auto targetWindow = findWindowArgs->ResultTargetWindow();
|
||||
const auto& targetWindowName = findWindowArgs->ResultTargetWindowName();
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_ProposeCommandline",
|
||||
@@ -463,7 +410,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// that goes with it. Alternatively, if we were given a magic windowing
|
||||
// constant, we can use that to look up an appropriate peasant.
|
||||
if (targetWindow >= 0 ||
|
||||
targetWindow == WindowingBehaviorUseName ||
|
||||
targetWindow == WindowingBehaviorUseExisting ||
|
||||
targetWindow == WindowingBehaviorUseAnyExisting)
|
||||
{
|
||||
@@ -483,9 +429,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
case WindowingBehaviorUseAnyExisting:
|
||||
windowID = _getMostRecentPeasantID(false);
|
||||
break;
|
||||
case WindowingBehaviorUseName:
|
||||
windowID = _lookupPeasantIdForName(targetWindowName);
|
||||
break;
|
||||
default:
|
||||
windowID = ::base::saturated_cast<uint64_t>(targetWindow);
|
||||
break;
|
||||
@@ -506,7 +449,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
if (auto targetPeasant{ _getPeasant(windowID) })
|
||||
{
|
||||
auto result{ winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(false) };
|
||||
result->WindowName(targetWindowName);
|
||||
|
||||
try
|
||||
{
|
||||
// This will raise the peasant's ExecuteCommandlineRequested
|
||||
@@ -554,7 +497,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
auto result{ winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(true) };
|
||||
result->Id(windowID);
|
||||
result->WindowName(targetWindowName);
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
@@ -566,69 +508,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
|
||||
// In this case, no usable ID was provided. Return { true, nullopt }
|
||||
auto result = winrt::make_self<Remoting::implementation::ProposeCommandlineResult>(true);
|
||||
result->WindowName(targetWindowName);
|
||||
return *result;
|
||||
}
|
||||
|
||||
void Monarch::_identifyWindows(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*args*/)
|
||||
{
|
||||
// Notify all the peasants to display their ID.
|
||||
for (const auto& [id, p] : _peasants)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.DisplayWindowId();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
// If this fails, we don't _really_ care. Just move on to the
|
||||
// next one. Someone else will clean up the dead peasant.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_identifyWindows_Failed",
|
||||
TraceLoggingInt64(id, "peasantID", "The ID of the peasant which we could not identify"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
}
|
||||
void Monarch::_renameRequested(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args)
|
||||
{
|
||||
bool successfullyRenamed = false;
|
||||
|
||||
try
|
||||
{
|
||||
args.Succeeded(false);
|
||||
auto name{ args.NewName() };
|
||||
// Try to find a peasant that currently has this name
|
||||
auto id = _lookupPeasantIdForName(name);
|
||||
if (auto p{ _getPeasant(id) })
|
||||
{
|
||||
// If there is one, then oh no! The requestor is not allowed to
|
||||
// be renamed.
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Succeeded(true);
|
||||
successfullyRenamed = true;
|
||||
}
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_renameRequested",
|
||||
TraceLoggingWideString(name.c_str(), "name", "The newly proposed name"),
|
||||
TraceLoggingInt64(successfullyRenamed, "successfullyRenamed", "true if the peasant is allowed to rename themselves to that name."),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
// If this fails, we don't _really_ care. The peasant died, but
|
||||
// they're the only one who cares about the result.
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Monarch_renameRequested_Failed",
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
return winrt::make<Remoting::implementation::ProposeCommandlineResult>(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,19 +67,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _getPeasant(uint64_t peasantID);
|
||||
uint64_t _getMostRecentPeasantID(bool limitToCurrentDesktop);
|
||||
uint64_t _lookupPeasantIdForName(const winrt::hstring& name);
|
||||
|
||||
void _peasantWindowActivated(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
|
||||
void _doHandleActivatePeasant(const winrt::com_ptr<winrt::Microsoft::Terminal::Remoting::implementation::WindowActivatedArgs>& args);
|
||||
void _clearOldMruEntries(const uint64_t peasantID);
|
||||
|
||||
void _identifyWindows(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _renameRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
|
||||
friend class RemotingUnitTests::RemotingTests;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,12 +9,11 @@ namespace Microsoft.Terminal.Remoting
|
||||
[default_interface] runtimeclass FindTargetWindowArgs {
|
||||
CommandlineArgs Args { get; };
|
||||
Int32 ResultTargetWindow;
|
||||
String ResultTargetWindowName;
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass ProposeCommandlineResult {
|
||||
Windows.Foundation.IReference<UInt64> Id { get; };
|
||||
String WindowName { get; };
|
||||
// TODO:projects/5 - also return the name here, if the name was set on the commandline
|
||||
Boolean ShouldCreateWindow { get; }; // If you name this `CreateWindow`, the compiler will explode
|
||||
}
|
||||
|
||||
|
||||
@@ -117,65 +117,4 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return _lastActivatedArgs;
|
||||
}
|
||||
|
||||
void Peasant::DisplayWindowId()
|
||||
{
|
||||
// Not worried about try/catching this. The handler is in AppHost, which
|
||||
// is in-proc for us.
|
||||
_DisplayWindowIdRequestedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
void Peasant::RequestIdentifyWindows()
|
||||
{
|
||||
bool successfullyNotified = false;
|
||||
|
||||
try
|
||||
{
|
||||
// Try/catch this, because the other side of this event is handled
|
||||
// by the monarch. The monarch might have died. If they have, this
|
||||
// will throw an exception. Just eat it, the election thread will
|
||||
// handle hooking up the new one.
|
||||
_IdentifyWindowsRequestedHandlers(*this, nullptr);
|
||||
successfullyNotified = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_RequestIdentifyWindows",
|
||||
TraceLoggingUInt64(GetID(), "peasantID", "Our ID"),
|
||||
TraceLoggingBoolean(successfullyNotified, "successfullyNotified", "true if we successfully notified the monarch"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
|
||||
void Peasant::RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args)
|
||||
{
|
||||
bool successfullyNotified = false;
|
||||
auto oldName{ _WindowName };
|
||||
try
|
||||
{
|
||||
// Try/catch this, because the other side of this event is handled
|
||||
// by the monarch. The monarch might have died. If they have, this
|
||||
// will throw an exception. Just eat it, the election thread will
|
||||
// handle hooking up the new one.
|
||||
_RenameRequestedHandlers(*this, args);
|
||||
if (args.Succeeded())
|
||||
{
|
||||
_WindowName = args.NewName();
|
||||
}
|
||||
successfullyNotified = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"Peasant_RequestRename",
|
||||
TraceLoggingUInt64(GetID(), "peasantID", "Our ID"),
|
||||
TraceLoggingWideString(oldName.c_str(), "oldName", "Our old name"),
|
||||
TraceLoggingWideString(args.NewName().c_str(), "newName", "The proposed name"),
|
||||
TraceLoggingBoolean(args.Succeeded(), "succeeded", "true if the monarch ok'd this new name for us."),
|
||||
TraceLoggingBoolean(successfullyNotified, "successfullyNotified", "true if we successfully notified the monarch"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "Peasant.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
#include "RenameRequestArgs.h"
|
||||
|
||||
namespace RemotingUnitTests
|
||||
{
|
||||
@@ -23,20 +22,12 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
|
||||
bool ExecuteCommandline(const winrt::Microsoft::Terminal::Remoting::CommandlineArgs& args);
|
||||
void ActivateWindow(const winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs& args);
|
||||
void RequestIdentifyWindows();
|
||||
void DisplayWindowId();
|
||||
void RequestRename(const winrt::Microsoft::Terminal::Remoting::RenameRequestArgs& args);
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs GetLastActivatedArgs();
|
||||
|
||||
winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
|
||||
GETSET_PROPERTY(winrt::hstring, WindowName, L"");
|
||||
|
||||
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::WindowActivatedArgs);
|
||||
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::CommandlineArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(DisplayWindowIdRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(RenameRequested, winrt::Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Remoting::RenameRequestArgs);
|
||||
|
||||
private:
|
||||
Peasant(const uint64_t testPID);
|
||||
|
||||
@@ -13,14 +13,6 @@ namespace Microsoft.Terminal.Remoting
|
||||
String CurrentDirectory();
|
||||
};
|
||||
|
||||
runtimeclass RenameRequestArgs
|
||||
{
|
||||
RenameRequestArgs(String newName);
|
||||
String NewName { get; };
|
||||
Boolean Succeeded;
|
||||
};
|
||||
|
||||
|
||||
runtimeclass WindowActivatedArgs
|
||||
{
|
||||
WindowActivatedArgs(UInt64 peasantID, Guid desktopID, Windows.Foundation.DateTime activatedTime);
|
||||
@@ -41,17 +33,9 @@ namespace Microsoft.Terminal.Remoting
|
||||
Boolean ExecuteCommandline(CommandlineArgs args);
|
||||
void ActivateWindow(WindowActivatedArgs args);
|
||||
WindowActivatedArgs GetLastActivatedArgs();
|
||||
String WindowName { get; };
|
||||
void RequestIdentifyWindows(); // Tells us to raise a IdentifyWindowsRequested
|
||||
void DisplayWindowId(); // Tells us to display its own ID (which causes a DisplayWindowIdRequested to be raised)
|
||||
|
||||
void RequestRename(RenameRequestArgs args); // Tells us to raise a RenameRequested
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<Object, WindowActivatedArgs> WindowActivated;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CommandlineArgs> ExecuteCommandlineRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> DisplayWindowIdRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameRequestArgs> RenameRequested;
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass Peasant : IPeasant
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
public:
|
||||
GETSET_PROPERTY(Windows::Foundation::IReference<uint64_t>, Id);
|
||||
GETSET_PROPERTY(winrt::hstring, WindowName, L"");
|
||||
GETSET_PROPERTY(bool, ShouldCreateWindow, true);
|
||||
|
||||
public:
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
#include "pch.h"
|
||||
#include "RenameRequestArgs.h"
|
||||
#include "RenameRequestArgs.g.cpp"
|
||||
@@ -1,30 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Class Name:
|
||||
- RenameRequestArgs.h
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "RenameRequestArgs.g.h"
|
||||
#include "../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
struct RenameRequestArgs : public RenameRequestArgsT<RenameRequestArgs>
|
||||
{
|
||||
GETSET_PROPERTY(winrt::hstring, NewName, L"");
|
||||
GETSET_PROPERTY(bool, Succeeded, false);
|
||||
|
||||
public:
|
||||
RenameRequestArgs(winrt::hstring newName) :
|
||||
_NewName{ newName } {};
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Remoting::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(RenameRequestArgs);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
struct WindowActivatedArgs : public WindowActivatedArgsT<WindowActivatedArgs>
|
||||
{
|
||||
GETSET_PROPERTY(uint64_t, PeasantID, 0);
|
||||
GETSET_PROPERTY(winrt::guid, DesktopID, {});
|
||||
GETSET_PROPERTY(winrt::guid, DesktopID);
|
||||
GETSET_PROPERTY(winrt::Windows::Foundation::DateTime, ActivatedTime, {});
|
||||
GETSET_PROPERTY(uint64_t, Hwnd, 0);
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "WindowManager.h"
|
||||
#include "MonarchFactory.h"
|
||||
#include "CommandlineArgs.h"
|
||||
#include "../inc/WindowingBehavior.h"
|
||||
#include "FindTargetWindowArgs.h"
|
||||
|
||||
#include "WindowManager.g.cpp"
|
||||
#include "../../types/inc/utils.hpp"
|
||||
@@ -71,7 +69,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
// Otherwise, the King will tell us if we should make a new window
|
||||
_shouldCreateWindow = _isKing;
|
||||
std::optional<uint64_t> givenID;
|
||||
winrt::hstring givenName = L""; // TODO:MG If we're the king, we might STILL WANT TO GET THE NAME. How do we get the name?
|
||||
if (!_isKing)
|
||||
{
|
||||
// The monarch may respond back "you should be a new
|
||||
@@ -89,7 +86,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
givenID = result.Id().Value();
|
||||
}
|
||||
givenName = result.WindowName();
|
||||
|
||||
// TraceLogging doesn't have a good solution for logging an
|
||||
// optional. So we have to repeat the calls here:
|
||||
if (givenID)
|
||||
@@ -98,7 +95,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
"WindowManager_ProposeCommandline",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
else
|
||||
@@ -107,7 +103,6 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
"WindowManager_ProposeCommandline",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingPointer(nullptr, "Id", "No ID provided"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
}
|
||||
@@ -115,50 +110,17 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
{
|
||||
// We're the monarch, we don't need to propose anything. We're just
|
||||
// going to do it.
|
||||
//
|
||||
// However, we _do_ need to ask what our name should be. It's
|
||||
// possible someone started the _first_ wt with something like `wt
|
||||
// -w king` as the commandline - we want to make sure we set our
|
||||
// name to "king".
|
||||
auto findWindowArgs{ winrt::make_self<Remoting::implementation::FindTargetWindowArgs>(args) };
|
||||
_raiseFindTargetWindowRequested(nullptr, *findWindowArgs);
|
||||
|
||||
auto responseId = findWindowArgs->ResultTargetWindow();
|
||||
if (responseId > 0)
|
||||
{
|
||||
givenID = ::base::saturated_cast<uint64_t>(responseId);
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingUInt64(givenID.value(), "Id", "The ID we should assign our peasant"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
else if (responseId == WindowingBehaviorUseName)
|
||||
{
|
||||
givenName = findWindowArgs->ResultTargetWindowName();
|
||||
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingWideString(givenName.c_str(), "Name", "The name we should assign this window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
TraceLoggingWrite(g_hRemotingProvider,
|
||||
"WindowManager_ProposeCommandline_AsMonarch",
|
||||
TraceLoggingBoolean(_shouldCreateWindow, "CreateWindow", "true iff we should create a new window"),
|
||||
TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE));
|
||||
}
|
||||
|
||||
if (_shouldCreateWindow)
|
||||
{
|
||||
// If we should create a new window, then instantiate our Peasant
|
||||
// instance, and tell that peasant to handle that commandline.
|
||||
_createOurPeasant({ givenID }, givenName);
|
||||
_createOurPeasant({ givenID });
|
||||
|
||||
// Spawn a thread to wait on the monarch, and handle the election
|
||||
if (!_isKing)
|
||||
@@ -246,17 +208,13 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
return (ourPID == kingPID);
|
||||
}
|
||||
|
||||
Remoting::IPeasant WindowManager::_createOurPeasant(std::optional<uint64_t> givenID,
|
||||
const winrt::hstring& givenName)
|
||||
Remoting::IPeasant WindowManager::_createOurPeasant(std::optional<uint64_t> givenID)
|
||||
{
|
||||
auto p = winrt::make_self<Remoting::implementation::Peasant>();
|
||||
if (givenID)
|
||||
{
|
||||
p->AssignID(givenID.value());
|
||||
}
|
||||
|
||||
// If the name wasn't specified, this will be an empty string.
|
||||
p->WindowName(givenName);
|
||||
_peasant = *p;
|
||||
|
||||
// Try to add us to the monarch. If that fails, try to find a monarch
|
||||
|
||||
@@ -54,8 +54,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation
|
||||
void _createMonarch();
|
||||
void _createMonarchAndCallbacks();
|
||||
bool _areWeTheKing();
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant(std::optional<uint64_t> givenID,
|
||||
const winrt::hstring& givenName);
|
||||
winrt::Microsoft::Terminal::Remoting::IPeasant _createOurPeasant(std::optional<uint64_t> givenID);
|
||||
|
||||
bool _performElection();
|
||||
void _createPeasantThread();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.201017.1" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -56,7 +56,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
|
||||
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||
|
||||
// Append a "\." to the given path, so that this will work in "C:\"
|
||||
std::wstring cmdline = fmt::format(L"\"{}\" -d \"{}\\.\"", GetWtExePath(), pszName.get());
|
||||
auto cmdline{ wil::str_printf<std::wstring>(LR"-("%s" -d "%s\.")-", GetWtExePath().c_str(), pszName.get()) };
|
||||
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
|
||||
nullptr,
|
||||
cmdline.data(),
|
||||
|
||||
@@ -27,8 +27,15 @@ Author(s):
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
struct __declspec(uuid("9f156763-7844-4dc4-b2b1-901f640f5155"))
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand>
|
||||
struct
|
||||
#if defined(WT_BRANDING_RELEASE)
|
||||
__declspec(uuid("9f156763-7844-4dc4-b2b1-901f640f5155"))
|
||||
#elif defined(WT_BRANDING_PREVIEW)
|
||||
__declspec(uuid("02db545a-3e20-46de-83a5-1329b1e88b6b"))
|
||||
#else // DEV
|
||||
__declspec(uuid("52065414-e077-47ec-a3ac-1cc5455e1b54"))
|
||||
#endif
|
||||
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand>
|
||||
{
|
||||
#pragma region IExplorerCommand
|
||||
STDMETHODIMP Invoke(IShellItemArray* psiItemArray,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "PlaceholderType.h"
|
||||
#include "PlaceholderType.g.cpp"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::ShellExtension::implementation
|
||||
{
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
|
||||
Module Name:
|
||||
- PlaceholderType.h
|
||||
|
||||
Abstract:
|
||||
- This class is just here to make our .wapproj play nicely with this project. If
|
||||
we don't define any winrt types, then we won't generate a .winmd, and the
|
||||
.wapproj will become _very_ mad at this project. So we'll use this placeholder
|
||||
class just to trick cppwinrt into generating a winmd for us. If we ever _do_
|
||||
add a real winrt type to this project, this can be removed.
|
||||
|
||||
Author(s):
|
||||
- Mike Griese - May 2020
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include <conattrs.hpp>
|
||||
#include "PlaceholderType.g.h"
|
||||
#include "../../cascadia/inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::ShellExtension::implementation
|
||||
{
|
||||
struct PlaceholderType : PlaceholderTypeT<PlaceholderType>
|
||||
{
|
||||
PlaceholderType() = default;
|
||||
GETSET_PROPERTY(int32_t, Placeholder, 42);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::ShellExtension::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(PlaceholderType);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
// This class is just here to make our .wapproj play nicely with this project.
|
||||
// If we don't define any winrt types, then we won't generate a .winmd, and the
|
||||
// .wapproj will become _very_ mad at this project. So we'll use this
|
||||
// placeholder class just to trick cppwinrt into generating a winmd for us. If
|
||||
// we ever _do_ add a real winrt type to this project, this can be removed.
|
||||
|
||||
namespace Microsoft.Terminal.ShellExtension
|
||||
{
|
||||
[default_interface] runtimeclass PlaceholderType {
|
||||
PlaceholderType();
|
||||
Int32 Placeholder
|
||||
{
|
||||
get;
|
||||
set;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetActivationFactory PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
<!-- build a dll, not exe (Application) -->
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<!-- sets a bunch of Windows Universal properties -->
|
||||
<OpenConsoleUniversalApp>true</OpenConsoleUniversalApp>
|
||||
<!-- suppress a bunch of Windows Universal properties from cppwinrt.props -->
|
||||
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\..\common.openconsole.props" Condition="'$(OpenConsoleDir)'==''" />
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
|
||||
@@ -21,23 +21,13 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="OpenTerminalHere.h" />
|
||||
<ClInclude Include="PlaceholderType.h">
|
||||
<DependentUpon>PlaceholderType.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaceholderType.cpp">
|
||||
<DependentUpon>PlaceholderType.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OpenTerminalHere.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="PlaceholderType.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
@@ -58,5 +48,40 @@
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
|
||||
|
||||
<!-- Override GetPackagingOutputs to roll up our DLL.
|
||||
This is a heavily stripped version of the one in Microsoft.*.AppxPackage.targets.
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<_ContinueOnError Condition="'$(BuildingProject)' == 'true'">true</_ContinueOnError>
|
||||
<_ContinueOnError Condition="'$(BuildingProject)' != 'true'">false</_ContinueOnError>
|
||||
</PropertyGroup>
|
||||
<Target Name="GetPackagingOutputs" Returns="@(PackagingOutputs)">
|
||||
<CallTarget Targets="BuiltProjectOutputGroup">
|
||||
<Output TaskParameter="TargetOutputs" ItemName="_BuiltProjectOutputGroupOutput" />
|
||||
</CallTarget>
|
||||
<ItemGroup>
|
||||
<_PackagingOutputsUnexpanded Include="%(_BuiltProjectOutputGroupOutput.FinalOutputPath)">
|
||||
<TargetPath>%(_BuiltProjectOutputGroupOutput.TargetPath)</TargetPath>
|
||||
<OutputGroup>BuiltProjectOutputGroup</OutputGroup>
|
||||
<ProjectName>$(ProjectName)</ProjectName>
|
||||
</_PackagingOutputsUnexpanded>
|
||||
</ItemGroup>
|
||||
<CallTarget Targets="DebugSymbolsProjectOutputGroup">
|
||||
<Output TaskParameter="TargetOutputs" ItemName="_DebugSymbolsProjectOutputGroupOutput" />
|
||||
</CallTarget>
|
||||
<ItemGroup>
|
||||
<_PackagingOutputsUnexpanded Include="%(_DebugSymbolsProjectOutputGroupOutput.FinalOutputPath)">
|
||||
<OutputGroup>DebugSymbolsProjectOutputGroup</OutputGroup>
|
||||
<ProjectName>$(ProjectName)</ProjectName>
|
||||
</_PackagingOutputsUnexpanded>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackagingOutputs Include="@(_PackagingOutputsUnexpanded)">
|
||||
<TargetPath>%(Filename)%(Extension)</TargetPath>
|
||||
</PackagingOutputs>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -4,22 +4,21 @@
|
||||
#include "pch.h"
|
||||
#include "OpenTerminalHere.h"
|
||||
|
||||
// For reference, see:
|
||||
// * https://docs.microsoft.com/en-us/cpp/cppcx/wrl/how-to-create-a-classic-com-component-using-wrl?view=vs-2019
|
||||
// * https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/move-to-winrt-from-wrl#porting-a-wrl-module-microsoftwrlmodule
|
||||
//
|
||||
// We don't need to implement DllGetActivationFactory or DllCanUnloadNow
|
||||
// manually, since the generated module.g.cpp will handle it for us, and will
|
||||
// handle our WRL types appropriately.
|
||||
//
|
||||
// We DO need to implement DllGetClassObject, because that's what explorer.exe
|
||||
// will call to attempt to create a class factory for our shell extension. The
|
||||
// CoCreatableClass macro in OpenTerminalHere.h will create the factory for us,
|
||||
// so that the GetClassObject call will work like magic.
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
|
||||
STDAPI DllCanUnloadNow()
|
||||
{
|
||||
return Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
|
||||
return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ IActivationFactory** factory)
|
||||
{
|
||||
return Module<InProc>::GetModule().GetActivationFactory(activatableClassId, factory);
|
||||
}
|
||||
|
||||
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _COM_Outptr_ void** ppv)
|
||||
{
|
||||
return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
|
||||
}
|
||||
|
||||
STDAPI_(BOOL)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.201017.1" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
|
||||
</packages>
|
||||
|
||||
@@ -35,8 +35,8 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
is unfortunately static. -->
|
||||
<SolidColorBrush x:Name="ErrorTextBrush" Color="{ThemeResource SystemErrorTextColor}" />
|
||||
|
||||
<!-- Suppress all padding except left around the tabs. The TabView looks far better like this. -->
|
||||
<Thickness x:Key="TabViewHeaderPadding">8,0,0,0</Thickness>
|
||||
<!-- Suppress top padding -->
|
||||
<Thickness x:Key="TabViewHeaderPadding">8,0,8,0</Thickness>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
|
||||
@@ -244,8 +244,8 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<SwitchToTabArgs>())
|
||||
{
|
||||
const auto handled = _SelectTab({ realArgs.TabIndex() });
|
||||
args.Handled(handled);
|
||||
_SelectTab({ realArgs.TabIndex() });
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,8 +544,8 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleTabSearch(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
void TerminalPage::_HandleOpenTabSearch(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
CommandPalette().SetTabs(_tabs, _mruTabs);
|
||||
CommandPalette().EnableTabSearchMode();
|
||||
@@ -668,59 +668,4 @@ namespace winrt::TerminalApp::implementation
|
||||
actionArgs.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleIdentifyWindows(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
// Raise a IdentifyWindowsRequested event. This will bubble up to the
|
||||
// AppLogic, to the AppHost, to the Peasant, to the Monarch, then get
|
||||
// distributed down to _all_ the Peasants, as to display info about the
|
||||
// window in _every_ Peasant window.
|
||||
//
|
||||
// This action is also buggy right now, because TeachingTips behave
|
||||
// weird in XAML Islands. See microsoft-ui-xaml#4382
|
||||
_IdentifyWindowsRequestedHandlers(*this, nullptr);
|
||||
args.Handled(true);
|
||||
}
|
||||
void TerminalPage::_HandleIdentifyWindow(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
// Unlike _HandleIdentifyWindow**s**, this event just displays the
|
||||
// window ID and name in the current window.
|
||||
IdentifyWindow();
|
||||
args.Handled(true);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleRenameWindow(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
if (args)
|
||||
{
|
||||
if (const auto& realArgs = args.ActionArgs().try_as<RenameWindowArgs>())
|
||||
{
|
||||
auto newName = realArgs.Name();
|
||||
auto request = winrt::make_self<implementation::RenameWindowRequestedArgs>(newName);
|
||||
_RenameWindowRequestedHandlers(*this, *request);
|
||||
}
|
||||
}
|
||||
args.Handled(false);
|
||||
}
|
||||
|
||||
void TerminalPage::_HandleOpenWindowRenamer(const IInspectable& /*sender*/,
|
||||
const ActionEventArgs& args)
|
||||
{
|
||||
WindowRenamer().IsOpen(true);
|
||||
|
||||
// PAIN: We can't immediately focus the textbox in the TeachingTip. It's
|
||||
// not technically focusable until it is opened. However, it doesn't
|
||||
// provide an even tto tell us when it is opened. That's tracked in
|
||||
// microsoft/microsoft-ui-xaml#1607. So for now, the user _needs_ to
|
||||
// click on the text box manually.
|
||||
//
|
||||
// We're also not using a ContentDialog for this, because in Xaml
|
||||
// Islands a text box in a ContentDialog won't recieve _any_ keypresses.
|
||||
// Fun!
|
||||
// WindowRenamerTextBox().Focus(FocusState::Programmatic);
|
||||
|
||||
args.Handled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,9 +185,9 @@ void AppCommandlineArgs::_buildParser()
|
||||
maximized->excludes(fullscreen);
|
||||
focus->excludes(fullscreen);
|
||||
|
||||
_app.add_option("-w,--window",
|
||||
_windowTarget,
|
||||
RS_A(L"CmdWindowTargetArgDesc"));
|
||||
_app.add_option<std::optional<int>, int>("-w,--window",
|
||||
_windowTarget,
|
||||
RS_A(L"CmdWindowTargetArgDesc"));
|
||||
|
||||
// Subcommands
|
||||
_buildNewTabParser();
|
||||
@@ -854,16 +854,16 @@ void AppCommandlineArgs::FullResetState()
|
||||
_exitMessage = "";
|
||||
_shouldExitEarly = false;
|
||||
|
||||
_windowTarget = "";
|
||||
_windowTarget = std::nullopt;
|
||||
}
|
||||
|
||||
std::string_view AppCommandlineArgs::GetTargetWindow() const noexcept
|
||||
std::optional<int> AppCommandlineArgs::GetTargetWindow() const noexcept
|
||||
{
|
||||
// // If the user provides _any_ negative number, then treat it as -1, for "use a new window".
|
||||
// if (_windowTarget.has_value() && *_windowTarget < 0)
|
||||
// {
|
||||
// return { -1 };
|
||||
// }
|
||||
// If the user provides _any_ negative number, then treat it as -1, for "use a new window".
|
||||
if (_windowTarget.has_value() && *_windowTarget < 0)
|
||||
{
|
||||
return { -1 };
|
||||
}
|
||||
|
||||
return _windowTarget;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
void DisableHelpInExitMessage();
|
||||
void FullResetState();
|
||||
|
||||
std::string_view GetTargetWindow() const noexcept;
|
||||
std::optional<int> GetTargetWindow() const noexcept;
|
||||
|
||||
private:
|
||||
static const std::wregex _commandDelimiterRegex;
|
||||
@@ -106,7 +106,7 @@ private:
|
||||
std::string _exitMessage;
|
||||
bool _shouldExitEarly{ false };
|
||||
|
||||
std::string _windowTarget{ "" };
|
||||
std::optional<int> _windowTarget{ std::nullopt };
|
||||
// Are you adding more args or attributes here? If they are not reset in _resetStateToDefault, make sure to reset them in FullResetState
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Model::NewTerminalArgs _getNewTerminalArgs(NewTerminalSubcommand& subcommand);
|
||||
|
||||