Compare commits
51 Commits
dev/lhecke
...
v1.7.1033.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
18
.github/actions/spelling/dictionary/apis.txt
vendored
@@ -6,6 +6,7 @@ bitfields
|
||||
CLASSNOTAVAILABLE
|
||||
cmdletbinding
|
||||
COLORPROPERTY
|
||||
COMDLG
|
||||
CXICON
|
||||
CYICON
|
||||
D2DERR_SHADER_COMPILE_FAILED
|
||||
@@ -14,6 +15,14 @@ DERR
|
||||
environstrings
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
dlldata
|
||||
DONTADDTORECENT
|
||||
environstrings
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
FILTERSPEC
|
||||
FORCEFILESYSTEM
|
||||
FORCEMINIMIZE
|
||||
frac
|
||||
fullkbd
|
||||
futex
|
||||
@@ -22,19 +31,22 @@ GETHIGHCONTRAST
|
||||
Hashtable
|
||||
HIGHCONTRASTON
|
||||
HIGHCONTRASTW
|
||||
hotkeys
|
||||
href
|
||||
IActivation
|
||||
IApp
|
||||
IAppearance
|
||||
IAsync
|
||||
IBind
|
||||
IBox
|
||||
IClass
|
||||
IConnection
|
||||
IComparable
|
||||
IConnection
|
||||
ICustom
|
||||
IDialog
|
||||
IDirect
|
||||
IExplorer
|
||||
IFile
|
||||
IInheritable
|
||||
IMap
|
||||
IObject
|
||||
@@ -59,6 +71,7 @@ NCLBUTTONDBLCLK
|
||||
NCRBUTTONDBLCLK
|
||||
NOAGGREGATION
|
||||
NOASYNC
|
||||
NOCHANGEDIR
|
||||
NOPROGRESS
|
||||
NOREDIRECTIONBITMAP
|
||||
ntprivapi
|
||||
@@ -68,10 +81,11 @@ otms
|
||||
OUTLINETEXTMETRICW
|
||||
overridable
|
||||
PAGESCROLL
|
||||
PICKFOLDERS
|
||||
pmr
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
REGCLS
|
||||
RETURNCMD
|
||||
rfind
|
||||
roundf
|
||||
RSHIFT
|
||||
|
||||
1
.github/actions/spelling/expect/expect.txt
vendored
@@ -2386,6 +2386,7 @@ titlebar
|
||||
TITLEISLINKNAME
|
||||
TJson
|
||||
tl
|
||||
TLambda
|
||||
TLEN
|
||||
Tlg
|
||||
Tlgdata
|
||||
|
||||
@@ -2410,8 +2410,6 @@ Global
|
||||
{21B7EA5E-1EF8-49B6-AC07-11714AF0E37D}.Release|x86.ActiveCfg = Release|Win32
|
||||
{21B7EA5E-1EF8-49B6-AC07-11714AF0E37D}.Release|x86.Build.0 = Release|Win32
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|Any CPU.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM.ActiveCfg = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM.Build.0 = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM.Deploy.0 = Debug|ARM
|
||||
@@ -2419,11 +2417,7 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM64.Build.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|ARM64.Deploy.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x64Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x64Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x64Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x86Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x86Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|DotNet_x86Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x64.ActiveCfg = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x64.Build.0 = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x64.Deploy.0 = Debug|x64
|
||||
@@ -2431,8 +2425,6 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x86.Build.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.AuditMode|x86.Deploy.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
@@ -2440,11 +2432,7 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x64Test.Build.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x64Test.Deploy.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x86Test.Build.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|DotNet_x86Test.Deploy.0 = Debug|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x64.Build.0 = Debug|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x64.Deploy.0 = Debug|x64
|
||||
@@ -2452,8 +2440,6 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x86.Build.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM.Build.0 = Release|ARM
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM.Deploy.0 = Release|ARM
|
||||
@@ -2461,11 +2447,7 @@ Global
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x64Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x64Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x64Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x86Test.ActiveCfg = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x86Test.Build.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|DotNet_x86Test.Deploy.0 = Release|Any CPU
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|x64.ActiveCfg = Release|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|x64.Build.0 = Release|x64
|
||||
{F75E29D0-D288-478B-8D83-2C190F321A3F}.Release|x64.Deploy.0 = Release|x64
|
||||
|
||||
@@ -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
|
||||
|
||||
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 |
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadWar
|
||||
USES_RESOURCE(L"FailedToWriteToSettings"),
|
||||
USES_RESOURCE(L"InvalidColorSchemeInCmd"),
|
||||
USES_RESOURCE(L"InvalidSplitSize"),
|
||||
USES_RESOURCE(L"FailedToParseStartupActions")
|
||||
USES_RESOURCE(L"FailedToParseStartupActions"),
|
||||
USES_RESOURCE(L"FailedToParseSubCommands"),
|
||||
};
|
||||
static const std::array<std::wstring_view, static_cast<uint32_t>(SettingsLoadErrors::ERRORS_SIZE)> settingsLoadErrorsLabels {
|
||||
USES_RESOURCE(L"NoProfilesText"),
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_itemTemplateSelector = Resources().Lookup(winrt::box_value(L"PaletteItemTemplateSelector")).try_as<PaletteItemTemplateSelector>();
|
||||
_listItemTemplate = Resources().Lookup(winrt::box_value(L"ListItemTemplate")).try_as<DataTemplate>();
|
||||
|
||||
_filteredActions = winrt::single_threaded_observable_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_nestedActionStack = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
_currentNestedCommands = winrt::single_threaded_vector<winrt::TerminalApp::FilteredCommand>();
|
||||
@@ -530,6 +533,15 @@ namespace winrt::TerminalApp::implementation
|
||||
// which will cause us to refresh the list of filterable commands.
|
||||
_searchBox().Text(L"");
|
||||
_searchBox().Focus(FocusState::Programmatic);
|
||||
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(_searchBox()) })
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
Automation::Peers::AutomationNotificationKind::ActionCompleted,
|
||||
Automation::Peers::AutomationNotificationProcessing::CurrentThenMostRecent,
|
||||
fmt::format(std::wstring_view{ RS_(L"CommandPalette_NestedCommandAnnouncement") }, ParentCommandName()),
|
||||
L"CommandPaletteNestingLevelChanged" /* unique name for this notification category */);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -768,7 +780,19 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (_currentMode == CommandPaletteMode::TabSearchMode || _currentMode == CommandPaletteMode::ActionMode)
|
||||
{
|
||||
_noMatchesText().Visibility(_filteredActions.Size() > 0 ? Visibility::Collapsed : Visibility::Visible);
|
||||
const auto currentNeedleHasResults{ _filteredActions.Size() > 0 };
|
||||
_noMatchesText().Visibility(currentNeedleHasResults ? Visibility::Collapsed : Visibility::Visible);
|
||||
if (!currentNeedleHasResults)
|
||||
{
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(_searchBox()) })
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
Automation::Peers::AutomationNotificationKind::ActionCompleted,
|
||||
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
|
||||
NoMatchesText(), // NoMatchesText contains the right text for the current mode
|
||||
L"CommandPaletteResultAnnouncement" /* unique name for this notification */);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -897,6 +921,9 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_currentMode = mode;
|
||||
|
||||
const auto currentlyVisible{ Visibility() == Visibility::Visible };
|
||||
|
||||
auto modeAnnouncementResourceKey{ USES_RESOURCE(L"CommandPaletteModeAnnouncement_ActionMode") };
|
||||
ParsedCommandLineText(L"");
|
||||
_searchBox().Text(L"");
|
||||
_searchBox().Select(_searchBox().Text().size(), 0);
|
||||
@@ -912,6 +939,7 @@ namespace winrt::TerminalApp::implementation
|
||||
NoMatchesText(RS_(L"TabSwitcher_NoMatchesText"));
|
||||
ControlName(RS_(L"TabSwitcherControlName"));
|
||||
PrefixCharacter(L"");
|
||||
modeAnnouncementResourceKey = USES_RESOURCE(L"CommandPaletteModeAnnouncement_TabSearchSwitchMode");
|
||||
break;
|
||||
}
|
||||
case CommandPaletteMode::CommandlineMode:
|
||||
@@ -919,6 +947,7 @@ namespace winrt::TerminalApp::implementation
|
||||
NoMatchesText(L"");
|
||||
ControlName(RS_(L"CommandPaletteControlName"));
|
||||
PrefixCharacter(L"");
|
||||
modeAnnouncementResourceKey = USES_RESOURCE(L"CommandPaletteModeAnnouncement_CommandlineMode");
|
||||
break;
|
||||
case CommandPaletteMode::ActionMode:
|
||||
default:
|
||||
@@ -926,9 +955,23 @@ namespace winrt::TerminalApp::implementation
|
||||
NoMatchesText(RS_(L"CommandPalette_NoMatchesText/Text"));
|
||||
ControlName(RS_(L"CommandPaletteControlName"));
|
||||
PrefixCharacter(L">");
|
||||
// modeAnnouncementResourceKey is already set to _ActionMode
|
||||
// We did this above to deduce the type (and make it easier on ourselves later).
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentlyVisible)
|
||||
{
|
||||
if (auto automationPeer{ Automation::Peers::FrameworkElementAutomationPeer::FromElement(_searchBox()) })
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
Automation::Peers::AutomationNotificationKind::ActionCompleted,
|
||||
Automation::Peers::AutomationNotificationProcessing::CurrentThenMostRecent,
|
||||
GetLibraryResourceString(modeAnnouncementResourceKey),
|
||||
L"CommandPaletteModeSwitch" /* unique ID for this notification */);
|
||||
}
|
||||
}
|
||||
|
||||
// The smooth remove/add animations that happen during
|
||||
// UpdateFilteredActions don't work very well when switching between
|
||||
// modes because of the sheer amount of remove/adds. So, let's just
|
||||
@@ -1067,4 +1110,81 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
_switchToMode(CommandPaletteMode::TabSearchMode);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This event is triggered when filteredActionView is looking for item container (ListViewItem)
|
||||
// to use to present the filtered actions.
|
||||
// GH#9288: unfortunately the default lookup seems to choose items with wrong data templates,
|
||||
// e.g., using DataTemplate rendering actions for tab palette items.
|
||||
// We handle this event by manually selecting an item from the cache.
|
||||
// If no item is found we allocate a new one.
|
||||
// Arguments:
|
||||
// - args: the ChoosingItemContainerEventArgs allowing to get container candidate suggested by the
|
||||
// system and replace it with another candidate if required.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_choosingItemContainer(
|
||||
Windows::UI::Xaml::Controls::ListViewBase const& /*sender*/,
|
||||
Windows::UI::Xaml::Controls::ChoosingItemContainerEventArgs const& args)
|
||||
{
|
||||
const auto dataTemplate = _itemTemplateSelector.SelectTemplate(args.Item());
|
||||
const auto itemContainer = args.ItemContainer();
|
||||
if (itemContainer && itemContainer.ContentTemplate() == dataTemplate)
|
||||
{
|
||||
// If the suggested candidate is OK simply remove it from the cache
|
||||
// (so we won't allocate it until it is released) and return
|
||||
_listViewItemsCache[dataTemplate].erase(itemContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need another candidate, let's look it up inside the cache
|
||||
auto& containersByTemplate = _listViewItemsCache[dataTemplate];
|
||||
if (!containersByTemplate.empty())
|
||||
{
|
||||
// There cache contains available items for required DataTemplate
|
||||
// Let's return one of them (and remove it from the cache)
|
||||
auto firstItem = containersByTemplate.begin();
|
||||
args.ItemContainer(*firstItem);
|
||||
containersByTemplate.erase(firstItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
ElementFactoryGetArgs factoryArgs{};
|
||||
const auto listViewItem = _listItemTemplate.GetElement(factoryArgs).try_as<Controls::ListViewItem>();
|
||||
listViewItem.ContentTemplate(dataTemplate);
|
||||
|
||||
if (dataTemplate == _itemTemplateSelector.NestedItemTemplate())
|
||||
{
|
||||
const auto helpText = winrt::box_value(RS_(L"CommandPalette_MoreOptions/[using:Windows.UI.Xaml.Automation]AutomationProperties/HelpText"));
|
||||
listViewItem.SetValue(Automation::AutomationProperties::HelpTextProperty(), helpText);
|
||||
}
|
||||
|
||||
args.ItemContainer(listViewItem);
|
||||
}
|
||||
}
|
||||
args.IsContainerPrepared(true);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - This event is triggered when the data item associate with filteredActionView list item is changing.
|
||||
// We check if the item is being recycled. In this case we return it to the cache
|
||||
// Arguments:
|
||||
// - args: the ContainerContentChangingEventArgs describing the container change
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void CommandPalette::_containerContentChanging(
|
||||
Windows::UI::Xaml::Controls::ListViewBase const& /*sender*/,
|
||||
Windows::UI::Xaml::Controls::ContainerContentChangingEventArgs const& args)
|
||||
{
|
||||
const auto itemContainer = args.ItemContainer();
|
||||
if (args.InRecycleQueue() && itemContainer && itemContainer.ContentTemplate())
|
||||
{
|
||||
_listViewItemsCache[itemContainer.ContentTemplate()].insert(itemContainer);
|
||||
itemContainer.DataContext(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemContainer.DataContext(args.Item());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,12 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::Foundation::Collections::IVector<winrt::TerminalApp::FilteredCommand> _commandLineHistory{ nullptr };
|
||||
::TerminalApp::AppCommandlineArgs _appArgs;
|
||||
|
||||
void _choosingItemContainer(Windows::UI::Xaml::Controls::ListViewBase const& sender, Windows::UI::Xaml::Controls::ChoosingItemContainerEventArgs const& args);
|
||||
void _containerContentChanging(Windows::UI::Xaml::Controls::ListViewBase const& sender, Windows::UI::Xaml::Controls::ContainerContentChangingEventArgs const& args);
|
||||
winrt::TerminalApp::PaletteItemTemplateSelector _itemTemplateSelector{ nullptr };
|
||||
std::unordered_map<Windows::UI::Xaml::DataTemplate, std::unordered_set<Windows::UI::Xaml::Controls::Primitives::SelectorItem>> _listViewItemsCache;
|
||||
Windows::UI::Xaml::DataTemplate _listItemTemplate;
|
||||
|
||||
friend class TerminalAppLocalTests::TabTests;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,166 +32,209 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<local:EmptyStringVisibilityConverter x:Key="CommandKeyChordVisibilityConverter"/>
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParsedCommandLineTextVisibilityConverter"/>
|
||||
<local:EmptyStringVisibilityConverter x:Key="ParentCommandVisibilityConverter"/>
|
||||
<local:HasNestedCommandsVisibilityConverter x:Key="HasNestedCommandsVisibilityConverter"/>
|
||||
<model:IconPathConverter x:Key="IconSourceConverter"/>
|
||||
|
||||
<DataTemplate x:Key="GeneralItemTemplate" x:DataType="local:FilteredCommand">
|
||||
|
||||
<!-- This HorizontalContentAlignment="Stretch" is important
|
||||
to make sure it takes the entire width of the line -->
|
||||
<DataTemplate x:Key="ListItemTemplate" x:DataType="local:FilteredCommand">
|
||||
<ListViewItem HorizontalContentAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Item.Name, Mode=OneWay}"
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}">
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}"/>
|
||||
</DataTemplate>
|
||||
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- icon -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- key chord -->
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
<DataTemplate x:Key="GeneralItemTemplate" x:DataType="local:FilteredCommand">
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- icon -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- key chord -->
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<IconSourceElement
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind Item.Icon,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource IconSourceConverter}}"/>
|
||||
<IconSourceElement
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind Item.Icon,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource IconSourceConverter}}"/>
|
||||
|
||||
<local:HighlightedTextControl
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}"/>
|
||||
<local:HighlightedTextControl
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}"/>
|
||||
|
||||
<!-- The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
it already did that because it was the list item's
|
||||
"AcceleratorKey". It's redundant. -->
|
||||
<Border
|
||||
Grid.Column="2"
|
||||
Visibility="{x:Bind Item.KeyChordText,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource CommandKeyChordVisibilityConverter}}"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Padding="2,0,2,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
<!-- The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
it already did that because it was the list item's
|
||||
"AcceleratorKey". It's redundant. -->
|
||||
<Border
|
||||
Grid.Column="2"
|
||||
Visibility="{x:Bind Item.KeyChordText,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource CommandKeyChordVisibilityConverter}}"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Padding="2,0,2,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
|
||||
<TextBlock
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
FontSize="12"
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
</Border>
|
||||
<TextBlock
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
FontSize="12"
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- xE70E is ChevronUp. Rotated 90 degrees, it's _ChevronRight_ -->
|
||||
<FontIcon
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
HorizontalAlignment="Right"
|
||||
Visibility="{x:Bind Item,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource HasNestedCommandsVisibilityConverter}}"
|
||||
Grid.Column="2">
|
||||
<DataTemplate x:Key="NestedItemTemplate" x:DataType="local:FilteredCommand">
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- icon -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- key chord -->
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<FontIcon.RenderTransform>
|
||||
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="90"/>
|
||||
</FontIcon.RenderTransform>
|
||||
</FontIcon>
|
||||
<IconSourceElement
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind Item.Icon,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource IconSourceConverter}}"/>
|
||||
|
||||
</Grid>
|
||||
</ListViewItem>
|
||||
<local:HighlightedTextControl
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}"/>
|
||||
|
||||
<!-- The block for the key chord is only visible
|
||||
when there's actual text set as the label. See
|
||||
CommandKeyChordVisibilityConverter for details.
|
||||
We're setting the accessibility view on the
|
||||
border and text block to Raw because otherwise,
|
||||
Narrator will read out the key chord. Problem is,
|
||||
it already did that because it was the list item's
|
||||
"AcceleratorKey". It's redundant. -->
|
||||
<Border
|
||||
Grid.Column="2"
|
||||
Visibility="{x:Bind Item.KeyChordText,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource CommandKeyChordVisibilityConverter}}"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Padding="2,0,2,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.AccessibilityView="Raw">
|
||||
|
||||
<TextBlock
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
FontSize="12"
|
||||
Text="{x:Bind Item.KeyChordText, Mode=OneWay}"
|
||||
AutomationProperties.AccessibilityView="Raw" />
|
||||
</Border>
|
||||
|
||||
<!-- xE70E is ChevronUp. Rotated 90 degrees, it's _ChevronRight_ -->
|
||||
<FontIcon
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Glyph=""
|
||||
HorizontalAlignment="Right"
|
||||
Grid.Column="2">
|
||||
|
||||
<FontIcon.RenderTransform>
|
||||
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="90"/>
|
||||
</FontIcon.RenderTransform>
|
||||
</FontIcon>
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="TabItemTemplate" x:DataType="local:FilteredCommand">
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8" AutomationProperties.Name="{x:Bind Item.Name, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- icon / progress -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- gutter for indicators -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- Indicators -->
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- This HorizontalContentAlignment="Stretch" is important
|
||||
to make sure it takes the entire width of the line -->
|
||||
<ListViewItem HorizontalContentAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Item.Name, Mode=OneWay}"
|
||||
AutomationProperties.AcceleratorKey="{x:Bind Item.KeyChordText, Mode=OneWay}">
|
||||
<mux:ProgressRing
|
||||
Grid.Column="0"
|
||||
IsActive="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsProgressRingActive, Mode=OneWay}"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsProgressRingActive, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsProgressRingIndeterminate, Mode=OneWay}"
|
||||
Value="{x:Bind Item.(local:TabPaletteItem.TabStatus).ProgressValue, Mode=OneWay}"
|
||||
MinHeight="0"
|
||||
MinWidth="0"
|
||||
Height="15"
|
||||
Width="15"/>
|
||||
|
||||
<Grid HorizontalAlignment="Stretch" ColumnSpacing="8" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- icon / progress -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- command label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- gutter for indicators -->
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- Indicators -->
|
||||
<ColumnDefinition Width="16"/>
|
||||
<!-- gutter for scrollbar -->
|
||||
</Grid.ColumnDefinitions>
|
||||
<IconSourceElement
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind Item.Icon,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource IconSourceConverter}}"/>
|
||||
|
||||
<mux:ProgressRing
|
||||
Grid.Column="0"
|
||||
IsActive="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsProgressRingActive, Mode=OneWay}"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsProgressRingActive, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsProgressRingIndeterminate, Mode=OneWay}"
|
||||
Value="{x:Bind Item.(local:TabPaletteItem.TabStatus).ProgressValue, Mode=OneWay}"
|
||||
MinHeight="0"
|
||||
MinWidth="0"
|
||||
Height="15"
|
||||
Width="15"/>
|
||||
<local:HighlightedTextControl
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}"/>
|
||||
|
||||
<IconSourceElement
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
IconSource="{x:Bind Item.Icon,
|
||||
Mode=OneWay,
|
||||
Converter={StaticResource IconSourceConverter}}"/>
|
||||
<StackPanel
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<local:HighlightedTextControl
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{x:Bind HighlightedName, Mode=OneWay}"/>
|
||||
<FontIcon
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).BellIndicator, Mode=OneWay}"
|
||||
Glyph=""
|
||||
FontSize="12"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<FontIcon
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsPaneZoomed, Mode=OneWay}"
|
||||
Glyph=""
|
||||
FontSize="12"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<FontIcon
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).BellIndicator, Mode=OneWay}"
|
||||
Glyph=""
|
||||
FontSize="12"
|
||||
Margin="0,0,8,0"/>
|
||||
<FontIcon x:Name="HeaderLockIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsReadOnlyActive, Mode=OneWay}"
|
||||
Glyph=""
|
||||
FontSize="12"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<FontIcon
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsPaneZoomed, Mode=OneWay}"
|
||||
Glyph=""
|
||||
FontSize="12"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<FontIcon x:Name="HeaderLockIcon"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{x:Bind Item.(local:TabPaletteItem.TabStatus).IsReadOnlyActive, Mode=OneWay}"
|
||||
Glyph=""
|
||||
FontSize="12"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ListViewItem>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<local:PaletteItemTemplateSelector x:Key="PaletteItemTemplateSelector" TabItemTemplate="{StaticResource TabItemTemplate}" GeneralItemTemplate="{StaticResource GeneralItemTemplate}"/>
|
||||
<local:PaletteItemTemplateSelector x:Key="PaletteItemTemplateSelector"
|
||||
TabItemTemplate="{StaticResource TabItemTemplate}"
|
||||
GeneralItemTemplate="{StaticResource GeneralItemTemplate}"
|
||||
NestedItemTemplate="{StaticResource NestedItemTemplate}"/>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
@@ -435,8 +478,9 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
AllowDrop="False"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="_listItemClicked"
|
||||
ItemsSource="{x:Bind FilteredActions}"
|
||||
ItemTemplateSelector="{StaticResource PaletteItemTemplateSelector}">
|
||||
ChoosingItemContainer="_choosingItemContainer"
|
||||
ContainerContentChanging="_containerContentChanging"
|
||||
ItemsSource="{x:Bind FilteredActions}">
|
||||
</ListView>
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "HasNestedCommandsVisibilityConverter.h"
|
||||
#include "HasNestedCommandsVisibilityConverter.g.cpp"
|
||||
|
||||
using namespace winrt::Windows;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
// Method Description:
|
||||
// - Attempt to convert something into another type. For the
|
||||
// HasNestedCommandsVisibilityConverter, we're gonna check if `value` is a
|
||||
// string, and try and convert it into a Visibility value. If the input
|
||||
// param wasn't a string, or was the empty string, we'll return
|
||||
// Visibility::Collapsed. Otherwise, we'll return Visible.
|
||||
|
||||
// Arguments:
|
||||
// - value: the input object to attempt to convert into a Visibility.
|
||||
// Return Value:
|
||||
// - Visible if the object was a string and wasn't the empty string.
|
||||
Foundation::IInspectable HasNestedCommandsVisibilityConverter::Convert(Foundation::IInspectable const& value,
|
||||
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
|
||||
Foundation::IInspectable const& /* parameter */,
|
||||
hstring const& /* language */)
|
||||
{
|
||||
const auto paletteItem{ value.try_as<winrt::TerminalApp::ActionPaletteItem>() };
|
||||
const auto& hasNestedCommands = paletteItem && paletteItem.Command().HasNestedCommands();
|
||||
return winrt::box_value(hasNestedCommands ? Visibility::Visible : Visibility::Collapsed);
|
||||
}
|
||||
|
||||
// unused for one-way bindings
|
||||
Foundation::IInspectable HasNestedCommandsVisibilityConverter::ConvertBack(Foundation::IInspectable const& /* value */,
|
||||
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
|
||||
Foundation::IInspectable const& /* parameter */,
|
||||
hstring const& /* language */)
|
||||
{
|
||||
throw hresult_not_implemented();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "HasNestedCommandsVisibilityConverter.g.h"
|
||||
#include "../inc/cppwinrt_utils.h"
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
struct HasNestedCommandsVisibilityConverter : HasNestedCommandsVisibilityConverterT<HasNestedCommandsVisibilityConverter>
|
||||
{
|
||||
HasNestedCommandsVisibilityConverter() = default;
|
||||
|
||||
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value,
|
||||
Windows::UI::Xaml::Interop::TypeName const& targetType,
|
||||
Windows::Foundation::IInspectable const& parameter,
|
||||
hstring const& language);
|
||||
|
||||
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value,
|
||||
Windows::UI::Xaml::Interop::TypeName const& targetType,
|
||||
Windows::Foundation::IInspectable const& parameter,
|
||||
hstring const& language);
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::TerminalApp::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(HasNestedCommandsVisibilityConverter);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
// See https://docs.microsoft.com/en-us/windows/uwp/data-binding/data-binding-quickstart
|
||||
|
||||
// We use the default attribute to declare IValueConverter as the default
|
||||
// interface. In the listing, HasNestedCommandsVisibilityConverter has only a
|
||||
// constructor, and no methods, so no default interface is generated for it.
|
||||
// The default attribute is optimal if you won't be adding instance members
|
||||
// to HasNestedCommandsVisibilityConverter, because no QueryInterface will be
|
||||
// required to call the IValueConverter methods
|
||||
runtimeclass HasNestedCommandsVisibilityConverter : [default] Windows.UI.Xaml.Data.IValueConverter
|
||||
{
|
||||
HasNestedCommandsVisibilityConverter();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -10,6 +10,9 @@
|
||||
#include "MinMaxCloseControl.h"
|
||||
|
||||
#include "MinMaxCloseControl.g.cpp"
|
||||
|
||||
#include <LibraryResources.h>
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
@@ -77,6 +80,7 @@ namespace winrt::TerminalApp::implementation
|
||||
MinimizeButton().Height(maximizedHeight);
|
||||
MaximizeButton().Height(maximizedHeight);
|
||||
CloseButton().Height(maximizedHeight);
|
||||
MaximizeToolTip().Text(RS_(L"WindowRestoreDownButtonToolTip"));
|
||||
break;
|
||||
|
||||
case WindowVisualState::WindowVisualStateNormal:
|
||||
@@ -87,6 +91,7 @@ namespace winrt::TerminalApp::implementation
|
||||
MinimizeButton().Height(windowedHeight);
|
||||
MaximizeButton().Height(windowedHeight);
|
||||
CloseButton().Height(windowedHeight);
|
||||
MaximizeToolTip().Text(RS_(L"WindowMaximizeButtonToolTip"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver" Color="White"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed" Color="#f1707a"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed" Color="Black"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackground" Color="#00e81123" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
|
||||
@@ -46,6 +48,8 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePointerOver" Color="White"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackgroundPressed" Color="#f1707a"/>
|
||||
<SolidColorBrush x:Key="CloseButtonStrokePressed" Color="Black"/>
|
||||
<SolidColorBrush x:Key="CloseButtonBackground" Color="#00e81123" />
|
||||
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<x:Double x:Key="CaptionButtonStrokeWidth">3.0</x:Double>
|
||||
@@ -188,6 +192,13 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<x:String x:Key="CaptionButtonPathWindowMaximized">M 0 2 h 8 v 8 h -8 v -8 M 2 2 v -2 h 8 v 8 h -2</x:String>
|
||||
</ResourceDictionary>
|
||||
</Button.Resources>
|
||||
<ToolTipService.ToolTip>
|
||||
<ToolTip>
|
||||
<TextBlock>
|
||||
<Run x:Name="MaximizeToolTip"/>
|
||||
</TextBlock>
|
||||
</ToolTip>
|
||||
</ToolTipService.ToolTip>
|
||||
</Button>
|
||||
<Button Height="{StaticResource CaptionButtonHeightWindowed}" MinWidth="46.0" Width="46.0"
|
||||
x:Name="CloseButton"
|
||||
@@ -203,12 +214,16 @@ the MIT License. See LICENSE in the project root for license information. -->
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="CloseButtonBackgroundPressed"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="CloseButtonStrokePointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="CloseButtonStrokePressed"/>
|
||||
<StaticResource x:Key="CaptionButtonBackground" ResourceKey="CloseButtonBackground" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor" ResourceKey="CloseButtonBackgroundColor" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="CloseButtonBackgroundPointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPressed" ResourceKey="CloseButtonBackgroundPressed"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePointerOver" ResourceKey="CloseButtonStrokePointerOver"/>
|
||||
<StaticResource x:Key="CaptionButtonStrokePressed" ResourceKey="CloseButtonStrokePressed"/>
|
||||
<StaticResource x:Key="CaptionButtonBackground" ResourceKey="CloseButtonBackground" />
|
||||
<StaticResource x:Key="CaptionButtonBackgroundColor" ResourceKey="CloseButtonBackgroundColor" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<StaticResource x:Key="CaptionButtonBackgroundPointerOver" ResourceKey="CloseButtonBackgroundPointerOver"/>
|
||||
|
||||
@@ -30,6 +30,13 @@ namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
return TabItemTemplate();
|
||||
}
|
||||
else if (const auto actionPaletteItem{ filteredCommand.Item().try_as<winrt::TerminalApp::ActionPaletteItem>() })
|
||||
{
|
||||
if (actionPaletteItem.Command().HasNestedCommands())
|
||||
{
|
||||
return NestedItemTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GeneralItemTemplate();
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::UI::Xaml::DataTemplate SelectTemplateCore(winrt::Windows::Foundation::IInspectable const&);
|
||||
|
||||
GETSET_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, TabItemTemplate);
|
||||
GETSET_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, NestedItemTemplate);
|
||||
GETSET_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, GeneralItemTemplate);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace TerminalApp
|
||||
PaletteItemTemplateSelector();
|
||||
|
||||
Windows.UI.Xaml.DataTemplate TabItemTemplate;
|
||||
Windows.UI.Xaml.DataTemplate NestedItemTemplate;
|
||||
Windows.UI.Xaml.DataTemplate GeneralItemTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +226,9 @@
|
||||
<value>• Found a keybinding with too many strings for the "keys" array. There should only be one string value in the "keys" array.</value>
|
||||
<comment>{Locked="\"keys\"","•"} This glyph is a bullet, used in a bulleted list.</comment>
|
||||
</data>
|
||||
<data name="FailedToParseSubCommands" xml:space="preserve">
|
||||
<value>• Failed to parse all subcommands of nested command.</value>
|
||||
</data>
|
||||
<data name="MissingRequiredParameter" xml:space="preserve">
|
||||
<value>• Found a keybinding that was missing a required parameter value. This keybinding will be ignored.</value>
|
||||
<comment>{Locked="•"} This glyph is a bullet, used in a bulleted list.</comment>
|
||||
@@ -359,9 +362,6 @@
|
||||
<data name="WindowMaximizeButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Maximize</value>
|
||||
</data>
|
||||
<data name="WindowMaximizeButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Maximize</value>
|
||||
</data>
|
||||
<data name="WindowMinimizeButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Minimize</value>
|
||||
</data>
|
||||
@@ -408,10 +408,10 @@
|
||||
<value>Do you want to close all tabs?</value>
|
||||
</data>
|
||||
<data name="CloseReadOnlyDialog.CloseButtonText" xml:space="preserve">
|
||||
<value>Close anyway</value>
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="CloseReadOnlyDialog.PrimaryButtonText" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
<value>Close anyway</value>
|
||||
</data>
|
||||
<data name="CloseReadOnlyDialog.Title" xml:space="preserve">
|
||||
<value>Warning</value>
|
||||
@@ -449,9 +449,25 @@
|
||||
<data name="CommandPalette_NoMatchesText.Text" xml:space="preserve">
|
||||
<value>No matching commands</value>
|
||||
</data>
|
||||
<data name="CommandPaletteModeAnnouncement_ActionMode" xml:space="preserve">
|
||||
<value>Action search mode</value>
|
||||
<comment>This text will be read aloud using assistive technologies when the command palette switches into action (command search) mode.</comment>
|
||||
</data>
|
||||
<data name="CommandPaletteModeAnnouncement_TabSearchSwitchMode" xml:space="preserve">
|
||||
<value>Tab title mode</value>
|
||||
<comment>This text will be read aloud using assistive technologies when the command palette switches into a mode that filters tab names.</comment>
|
||||
</data>
|
||||
<data name="CommandPaletteModeAnnouncement_CommandlineMode" xml:space="preserve">
|
||||
<value>Command-line mode</value>
|
||||
<comment>This text will be read aloud using assistive technologies when the command palette switches into the raw commandline parsing mode.</comment>
|
||||
</data>
|
||||
<data name="CommandPalette_NestedCommandAnnouncement" xml:space="preserve">
|
||||
<value>More options for "{}"</value>
|
||||
<comment>This text will be read aloud using assistive technologies when the user selects a command that has additional options. The {} will be expanded to the name of the command containing more options.</comment>
|
||||
</data>
|
||||
<data name="CommandPalette_ParsedCommandLine" xml:space="preserve">
|
||||
<value>Executing command line will invoke the following commands:</value>
|
||||
<comment>Will be followed by a list of strings describing parsed commands</comment>
|
||||
<comment>Will be followed by a list of strings describing parsed commands</comment>
|
||||
</data>
|
||||
<data name="CommandPalette_FailedParsingCommandLine" xml:space="preserve">
|
||||
<value>Failed parsing command line:</value>
|
||||
@@ -559,4 +575,13 @@
|
||||
<data name="ClipboardTextHeader.Text" xml:space="preserve">
|
||||
<value>Clipboard contents (preview):</value>
|
||||
</data>
|
||||
<data name="CommandPalette_MoreOptions.[using:Windows.UI.Xaml.Automation]AutomationProperties.HelpText" xml:space="preserve">
|
||||
<value>More options</value>
|
||||
</data>
|
||||
<data name="WindowMaximizeButtonToolTip" xml:space="preserve">
|
||||
<value>Maximize</value>
|
||||
</data>
|
||||
<data name="WindowRestoreDownButtonToolTip" xml:space="preserve">
|
||||
<value>Restore Down</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace winrt::TerminalApp::implementation
|
||||
// - true if we handled the event was handled, else false.
|
||||
bool ShortcutActionDispatch::DoAction(const ActionAndArgs& actionAndArgs)
|
||||
{
|
||||
if (!actionAndArgs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& action = actionAndArgs.Action();
|
||||
const auto& args = actionAndArgs.Args();
|
||||
auto eventArgs = args ? ActionEventArgs{ args } :
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace winrt::TerminalApp::implementation
|
||||
Controls::MenuFlyoutItem closeTabMenuItem;
|
||||
Controls::FontIcon closeSymbol;
|
||||
closeSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
|
||||
closeSymbol.Glyph(L"\xE8BB");
|
||||
closeSymbol.Glyph(L"\xE711");
|
||||
|
||||
closeTabMenuItem.Click([weakThis](auto&&, auto&&) {
|
||||
if (auto tab{ weakThis.get() })
|
||||
@@ -62,7 +62,6 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Build the menu
|
||||
Controls::MenuFlyout newTabFlyout;
|
||||
newTabFlyout.Items().Append(_CreateCloseSubMenu());
|
||||
newTabFlyout.Items().Append(closeTabMenuItem);
|
||||
TabViewItem().ContextFlyout(newTabFlyout);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,18 @@ namespace winrt::TerminalApp::implementation
|
||||
// We'll only process the KeyUp event if we received an initial KeyDown event first.
|
||||
// Avoids issue immediately closing the tab rename when we see the enter KeyUp event that was
|
||||
// sent to the command palette to trigger the openTabRenamer action in the first place.
|
||||
HeaderRenamerTextBox().KeyDown([&](auto&&, auto&&) {
|
||||
HeaderRenamerTextBox().KeyDown([&](auto&&, auto&& e) {
|
||||
_receivedKeyDown = true;
|
||||
|
||||
// GH#9632 - mark navigation buttons as handled.
|
||||
// This should prevent the tab view to use this key for navigation between tabs
|
||||
if (e.OriginalKey() == Windows::System::VirtualKey::Down ||
|
||||
e.OriginalKey() == Windows::System::VirtualKey::Up ||
|
||||
e.OriginalKey() == Windows::System::VirtualKey::Left ||
|
||||
e.OriginalKey() == Windows::System::VirtualKey::Right)
|
||||
{
|
||||
e.Handled(true);
|
||||
}
|
||||
});
|
||||
|
||||
// NOTE: (Preview)KeyDown does not work here. If you use that, we'll
|
||||
|
||||
@@ -124,9 +124,6 @@
|
||||
<ClInclude Include="EmptyStringVisibilityConverter.h">
|
||||
<DependentUpon>EmptyStringVisibilityConverter.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HasNestedCommandsVisibilityConverter.h">
|
||||
<DependentUpon>HasNestedCommandsVisibilityConverter.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Pane.h" />
|
||||
<ClInclude Include="ColorHelper.h" />
|
||||
<ClInclude Include="TerminalSettings.h">
|
||||
@@ -204,9 +201,6 @@
|
||||
<ClCompile Include="EmptyStringVisibilityConverter.cpp">
|
||||
<DependentUpon>EmptyStringVisibilityConverter.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HasNestedCommandsVisibilityConverter.cpp">
|
||||
<DependentUpon>HasNestedCommandsVisibilityConverter.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Pane.cpp" />
|
||||
<ClCompile Include="Pane.LayoutSizeNode.cpp" />
|
||||
<ClCompile Include="ColorHelper.cpp" />
|
||||
@@ -293,7 +287,6 @@
|
||||
</Midl>
|
||||
<Midl Include="FilteredCommand.idl" />
|
||||
<Midl Include="EmptyStringVisibilityConverter.idl" />
|
||||
<Midl Include="HasNestedCommandsVisibilityConverter.idl" />
|
||||
<Midl Include="TerminalSettings.idl" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= Misc Files ======================== -->
|
||||
|
||||