From 3cc82a51d8bc8ab72a55e0ec18e26e02f20a8fef Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Sat, 30 Mar 2024 00:15:46 +0100 Subject: [PATCH 1/9] Replace til::some with til::small_vector (#16952) `til::small_vector` had a bug: Its internal backing buffer didn't prevent default initialization! Wrapping it in an `union` fixed that. `til::some` had the same issue, but thinking about it I realized we don't need both classes to exist, so I removed `til::some` since `til::small_vector` is more flexible. Checking the assembly, I noticed that `til::small_vector` with the `union` fix produced a more compact result. I also noticed that in combination with function calls and inlining the bit-wise ANDs in the point/size/rect boolean operators produced poor-ish results. Since their impact on performance is negligible to begin with I simplified that code slightly. Finally, I noticed that the boolean operator for `til::point` was incorrect since it checked for `>0` instead of `>=0`. Luckily nothing seemed to have used that operator yet. (= No inbox regression.) --- src/inc/til/point.h | 2 +- src/inc/til/rect.h | 18 +- src/inc/til/rle.h | 2 - src/inc/til/size.h | 2 +- src/inc/til/small_vector.h | 7 +- src/inc/til/some.h | 267 -------------- src/renderer/atlas/BackendD3D.h | 1 - src/renderer/gdi/paint.cpp | 2 - src/server/ApiMessage.h | 2 - src/til/ut_til/BitmapTests.cpp | 8 +- src/til/ut_til/PointTests.cpp | 18 + src/til/ut_til/RectangleTests.cpp | 64 ++-- src/til/ut_til/SizeTests.cpp | 30 +- src/til/ut_til/SmallVectorTests.cpp | 2 - src/til/ut_til/SomeTests.cpp | 340 ------------------ src/til/ut_til/UnicodeTests.cpp | 4 +- src/til/ut_til/sources | 1 - src/til/ut_til/til.unit.tests.vcxproj | 4 +- src/til/ut_til/til.unit.tests.vcxproj.filters | 6 +- src/types/inc/IInputEvent.hpp | 2 - src/types/inc/viewport.hpp | 2 +- 21 files changed, 77 insertions(+), 707 deletions(-) delete mode 100644 src/inc/til/some.h delete mode 100644 src/til/ut_til/SomeTests.cpp diff --git a/src/inc/til/point.h b/src/inc/til/point.h index 4da8d5c6ddb..678afe706f6 100644 --- a/src/inc/til/point.h +++ b/src/inc/til/point.h @@ -58,7 +58,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" constexpr explicit operator bool() const noexcept { - return (x > 0) & (y > 0); + return x >= 0 && y >= 0; } constexpr bool operator<(const point other) const noexcept diff --git a/src/inc/til/rect.h b/src/inc/til/rect.h index 7ad7fe7ab7d..bc7b07b6c83 100644 --- a/src/inc/til/rect.h +++ b/src/inc/til/rect.h @@ -4,11 +4,11 @@ #pragma once #include "bit.h" -#include "some.h" #include "math.h" #include "size.h" #include "point.h" #include "operators.h" +#include "small_vector.h" namespace til // Terminal Implementation Library. Also: "Today I Learned" { @@ -31,8 +31,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" explicit constexpr operator bool() const noexcept { - return (left >= 0) & (top >= 0) & - (right >= left) & (bottom >= top); + return left >= 0 && top >= 0 && right >= left && bottom >= top; } }; @@ -204,8 +203,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" explicit constexpr operator bool() const noexcept { - return (left >= 0) & (top >= 0) & - (right > left) & (bottom > top); + return left >= 0 && top >= 0 && right > left && bottom > top; } constexpr const_iterator begin() const @@ -294,9 +292,9 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" } // - = subtract - constexpr some operator-(const rect& other) const + small_vector operator-(const rect& other) const { - some result; + small_vector result; // We could have up to four rectangles describing the area resulting when you take removeMe out of main. // Find the intersection of the two so we know which bits of removeMe are actually applicable @@ -566,14 +564,12 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" constexpr bool contains(point pt) const noexcept { - return (pt.x >= left) & (pt.x < right) & - (pt.y >= top) & (pt.y < bottom); + return pt.x >= left && pt.x < right && pt.y >= top && pt.y < bottom; } constexpr bool contains(const rect& rc) const noexcept { - return (rc.left >= left) & (rc.top >= top) & - (rc.right <= right) & (rc.bottom <= bottom); + return rc.left >= left && rc.top >= top && rc.right <= right && rc.bottom <= bottom; } template diff --git a/src/inc/til/rle.h b/src/inc/til/rle.h index 34b6c929a0b..99bdf734c45 100644 --- a/src/inc/til/rle.h +++ b/src/inc/til/rle.h @@ -3,8 +3,6 @@ #pragma once -#include "small_vector.h" - #ifdef UNIT_TESTING class RunLengthEncodingTests; #endif diff --git a/src/inc/til/size.h b/src/inc/til/size.h index 72dbb602852..98800ad7539 100644 --- a/src/inc/til/size.h +++ b/src/inc/til/size.h @@ -39,7 +39,7 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" constexpr explicit operator bool() const noexcept { - return (width > 0) & (height > 0); + return width > 0 && height > 0; } constexpr size operator+(const size other) const diff --git a/src/inc/til/small_vector.h b/src/inc/til/small_vector.h index f078d37fbe4..b47cd1ead14 100644 --- a/src/inc/til/small_vector.h +++ b/src/inc/til/small_vector.h @@ -652,7 +652,7 @@ namespace til reference emplace_back(Args&&... args) { const auto new_size = _ensure_fits(1); - const auto it = new (_data + _size) T(std::forward(args)...); + const auto it = std::construct_at(_data + _size, std::forward(args)...); _size = new_size; return *it; } @@ -930,7 +930,10 @@ namespace til T* _data; size_t _capacity; size_t _size; - T _buffer[N]; + union + { + T _buffer[N]; + }; }; } diff --git a/src/inc/til/some.h b/src/inc/til/some.h deleted file mode 100644 index ec34a470ca4..00000000000 --- a/src/inc/til/some.h +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#pragma once - -#include - -namespace til // Terminal Implementation Library. Also: "Today I Learned" -{ - template - class some - { - private: - std::array _array; - size_t _used; - -#ifdef UNIT_TESTING - friend class SomeTests; -#endif - - public: - using value_type = T; - using size_type = size_t; - using difference_type = ptrdiff_t; - using pointer = T*; - using const_pointer = const T*; - using reference = T&; - using const_reference = const T&; - - using iterator = typename decltype(_array)::iterator; - using const_iterator = typename decltype(_array)::const_iterator; - - using reverse_iterator = typename decltype(_array)::reverse_iterator; - using const_reverse_iterator = typename decltype(_array)::const_reverse_iterator; - - constexpr some() noexcept : - _array{}, - _used{ 0 } - { - } - - constexpr some(std::initializer_list init) - { - if (init.size() > N) - { - _invalidArg(); - } - - std::copy(init.begin(), init.end(), _array.begin()); - _used = init.size(); - } - - constexpr bool operator==(const til::some& other) const noexcept - { - return std::equal(cbegin(), cend(), other.cbegin(), other.cend()); - } - - constexpr bool operator!=(const til::some& other) const noexcept - { - return !(*this == other); - } - - constexpr void fill(const T& _Value) - { - _array.fill(_Value); - _used = N; - } - - constexpr void swap(some& _Other) noexcept(std::is_nothrow_swappable_v) - { - _array.swap(_Other._array); - std::swap(_used, _Other._used); - } - - constexpr const_iterator begin() const noexcept - { - return _array.begin(); - } - - constexpr const_iterator end() const noexcept - { - return _array.begin() + _used; - } - - constexpr const_reverse_iterator rbegin() const noexcept - { - return const_reverse_iterator(end()); - } - - constexpr const_reverse_iterator rend() const noexcept - { - return const_reverse_iterator(begin()); - } - - constexpr const_iterator cbegin() const noexcept - { - return begin(); - } - - constexpr const_iterator cend() const noexcept - { - return end(); - } - - constexpr const_reverse_iterator crbegin() const noexcept - { - return rbegin(); - } - - constexpr const_reverse_iterator crend() const noexcept - { - return rend(); - } - - constexpr size_type size() const noexcept - { - return _used; - } - - constexpr size_type max_size() const noexcept - { - return N; - } - - constexpr bool empty() const noexcept - { - return !_used; - } - - constexpr void clear() noexcept - { - _used = 0; - _array = {}; // should free members, if necessary. - } - - constexpr const_reference at(size_type pos) const - { - if (_used <= pos) - { - _outOfRange(); - } - - return _array[pos]; - } - - constexpr const_reference operator[](size_type pos) const noexcept - { - return _array[pos]; - } - - constexpr const_reference front() const noexcept - { - return _array[0]; - } - - constexpr const_reference back() const noexcept - { - return _array[_used - 1]; - } - - constexpr const T* data() const noexcept - { - return _array.data(); - } - - constexpr void push_back(const T& val) - { - if (_used >= N) - { - _outOfRange(); - } - - til::at(_array, _used) = val; - - ++_used; - } - - constexpr void push_back(T&& val) - { - if (_used >= N) - { - _outOfRange(); - } - - til::at(_array, _used) = std::move(val); - - ++_used; - } - - constexpr void pop_back() - { - if (_used <= 0) - { - _outOfRange(); - } - - --_used; - - til::at(_array, _used) = 0; - } - - [[noreturn]] constexpr void _invalidArg() const - { - throw std::invalid_argument("invalid argument"); - } - - [[noreturn]] constexpr void _outOfRange() const - { - throw std::out_of_range("invalid some subscript"); - } - - std::wstring to_string() const - { - std::wstringstream wss; - wss << std::endl - << L"Some contains " << size() << " of max size " << max_size() << ":" << std::endl; - wss << L"Elements:" << std::endl; - - for (auto& item : *this) - { - wss << L"\t- " << item.to_string() << std::endl; - } - - return wss.str(); - } - }; -} - -#ifdef __WEX_COMMON_H__ -namespace WEX::TestExecution -{ - template - class VerifyOutputTraits<::til::some> - { - public: - static WEX::Common::NoThrowString ToString(const ::til::some& some) - { - return WEX::Common::NoThrowString(some.to_string().c_str()); - } - }; - - template - class VerifyCompareTraits<::til::some, ::til::some> - { - public: - static bool AreEqual(const ::til::some& expected, const ::til::some& actual) noexcept - { - return expected == actual; - } - - static bool AreSame(const ::til::some& expected, const ::til::some& actual) noexcept - { - return &expected == &actual; - } - - static bool IsLessThan(const ::til::some& expectedLess, const ::til::some& expectedGreater) = delete; - - static bool IsGreaterThan(const ::til::some& expectedGreater, const ::til::some& expectedLess) = delete; - - static bool IsNull(const ::til::some& object) noexcept - { - return object == til::some{}; - } - }; - -}; -#endif diff --git a/src/renderer/atlas/BackendD3D.h b/src/renderer/atlas/BackendD3D.h index 25833b831dc..6a12e704a4d 100644 --- a/src/renderer/atlas/BackendD3D.h +++ b/src/renderer/atlas/BackendD3D.h @@ -5,7 +5,6 @@ #include #include -#include #include "Backend.h" diff --git a/src/renderer/gdi/paint.cpp b/src/renderer/gdi/paint.cpp index 29f8dfc43ad..c449b4d0835 100644 --- a/src/renderer/gdi/paint.cpp +++ b/src/renderer/gdi/paint.cpp @@ -4,8 +4,6 @@ #include "precomp.h" #include "gdirenderer.hpp" -#include - #include "../inc/unicode.hpp" #pragma hdrstop diff --git a/src/server/ApiMessage.h b/src/server/ApiMessage.h index d730cff9e00..6c1809aa9d7 100644 --- a/src/server/ApiMessage.h +++ b/src/server/ApiMessage.h @@ -20,8 +20,6 @@ Revision History: #include "ApiMessageState.h" #include "IApiRoutines.h" -#include - class ConsoleProcessHandle; class ConsoleHandleData; diff --git a/src/til/ut_til/BitmapTests.cpp b/src/til/ut_til/BitmapTests.cpp index ee093f52a79..b17bf0fff4e 100644 --- a/src/til/ut_til/BitmapTests.cpp +++ b/src/til/ut_til/BitmapTests.cpp @@ -868,7 +868,7 @@ class BitmapTests // C _ D D // _ _ E _ // _ F F _ - til::some expected; + std::vector expected; expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } }); expected.push_back(til::rect{ til::point{ 3, 0 }, til::size{ 1, 1 } }); expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 1, 1 } }); @@ -877,7 +877,7 @@ class BitmapTests expected.push_back(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } }); Log::Comment(L"Run the iterator and collect the runs."); - til::some actual; + std::vector actual; for (auto run : map.runs()) { actual.push_back(run); @@ -1006,7 +1006,7 @@ class BitmapTests // C _ D D // _ _ E _ // _ F F _ - til::some expected; + std::vector expected; expected.push_back(til::rect{ til::point{ 0, 0 }, til::size{ 2, 1 } }); expected.push_back(til::rect{ til::point{ 3, 0 }, til::size{ 1, 1 } }); expected.push_back(til::rect{ til::point{ 0, 1 }, til::size{ 1, 1 } }); @@ -1015,7 +1015,7 @@ class BitmapTests expected.push_back(til::rect{ til::point{ 1, 3 }, til::size{ 2, 1 } }); Log::Comment(L"Run the iterator and collect the runs."); - til::some actual; + std::vector actual; for (auto run : map.runs()) { actual.push_back(run); diff --git a/src/til/ut_til/PointTests.cpp b/src/til/ut_til/PointTests.cpp index cd069153c77..738847cee75 100644 --- a/src/til/ut_til/PointTests.cpp +++ b/src/til/ut_til/PointTests.cpp @@ -221,6 +221,24 @@ class PointTests } } + TEST_METHOD(Boolean) + { + SetVerifyOutput verifyOutputScope{ VerifyOutputSettings::LogOnlyFailures }; + + static constexpr til::CoordType values[] = { til::CoordTypeMin, -1, 0, 1, til::CoordTypeMax }; + + for (const auto x : values) + { + for (const auto y : values) + { + const til::point p{ x, y }; + const auto expected = x >= 0 && y >= 0; + const auto actual = static_cast(p); + VERIFY_ARE_EQUAL(expected, actual); + } + } + } + TEST_METHOD(Addition) { Log::Comment(L"Addition of two things that should be in bounds."); diff --git a/src/til/ut_til/RectangleTests.cpp b/src/til/ut_til/RectangleTests.cpp index 8709d1f8d66..f7a882fb987 100644 --- a/src/til/ut_til/RectangleTests.cpp +++ b/src/til/ut_til/RectangleTests.cpp @@ -300,22 +300,26 @@ class RectangleTests TEST_METHOD(Boolean) { - BEGIN_TEST_METHOD_PROPERTIES() - TEST_METHOD_PROPERTY(L"Data:left", L"{0,10}") - TEST_METHOD_PROPERTY(L"Data:top", L"{0,10}") - TEST_METHOD_PROPERTY(L"Data:right", L"{0,10}") - TEST_METHOD_PROPERTY(L"Data:bottom", L"{0,10}") - END_TEST_METHOD_PROPERTIES() + SetVerifyOutput verifyOutputScope{ VerifyOutputSettings::LogOnlyFailures }; - til::CoordType left, top, right, bottom; - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"left", left)); - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"top", top)); - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"right", right)); - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"bottom", bottom)); + static constexpr til::CoordType values[] = { til::CoordTypeMin, -1, 0, 1, til::CoordTypeMax }; - const auto expected = left < right && top < bottom; - const til::rect actual{ left, top, right, bottom }; - VERIFY_ARE_EQUAL(expected, (bool)actual); + for (const auto left : values) + { + for (const auto top : values) + { + for (const auto right : values) + { + for (const auto bottom : values) + { + const til::rect r{ left, top, right, bottom }; + const auto expected = left >= 0 && top >= 0 && right > left && bottom > top; + const auto actual = static_cast(r); + VERIFY_ARE_EQUAL(expected, actual); + } + } + } + } } TEST_METHOD(OrUnion) @@ -364,7 +368,7 @@ class RectangleTests const auto removal = original; // Since it's the same rectangle, nothing's left. We should get no results. - const til::some expected; + const til::small_vector expected; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); } @@ -375,7 +379,7 @@ class RectangleTests const til::rect removal{ 12, 12, 15, 15 }; // Since they don't overlap, we expect the original to be given back. - const til::some expected{ original }; + const til::small_vector expected{ original }; const auto actual = original - removal; VERIFY_ARE_EQUAL(expected, actual); } @@ -401,7 +405,7 @@ class RectangleTests const til::rect original{ 0, 0, 10, 10 }; const til::rect removal{ -12, 3, 15, 15 }; - const til::some expected{ + const til::small_vector expected{ til::rect{ original.left, original.top, original.right, removal.top } }; const auto actual = original - removal; @@ -428,7 +432,7 @@ class RectangleTests const til::rect original{ 0, 0, 10, 10 }; const til::rect removal{ 3, 3, 15, 15 }; - const til::some expected{ + const til::small_vector expected{ til::rect{ original.left, original.top, original.right, removal.top }, til::rect{ original.left, removal.top, removal.left, original.bottom } }; @@ -452,7 +456,7 @@ class RectangleTests const til::rect original{ 0, 0, 10, 10 }; const til::rect removal{ 3, 3, 15, 6 }; - const til::some expected{ + const til::small_vector expected{ til::rect{ original.left, original.top, original.right, removal.top }, til::rect{ original.left, removal.bottom, original.right, original.bottom }, til::rect{ original.left, removal.top, removal.left, removal.bottom } @@ -483,7 +487,7 @@ class RectangleTests const til::rect original{ 0, 0, 10, 10 }; const til::rect removal{ 3, 3, 6, 6 }; - const til::some expected{ + const til::small_vector expected{ til::rect{ original.left, original.top, original.right, removal.top }, til::rect{ original.left, removal.bottom, original.right, original.bottom }, til::rect{ original.left, removal.top, removal.left, removal.bottom }, @@ -706,26 +710,6 @@ class RectangleTests VERIFY_ARE_EQUAL(expected, rc.size()); } - TEST_METHOD(Empty) - { - BEGIN_TEST_METHOD_PROPERTIES() - TEST_METHOD_PROPERTY(L"Data:left", L"{0,10}") - TEST_METHOD_PROPERTY(L"Data:top", L"{0,10}") - TEST_METHOD_PROPERTY(L"Data:right", L"{0,10}") - TEST_METHOD_PROPERTY(L"Data:bottom", L"{0,10}") - END_TEST_METHOD_PROPERTIES() - - til::CoordType left, top, right, bottom; - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"left", left)); - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"top", top)); - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"right", right)); - VERIFY_SUCCEEDED_RETURN(TestData::TryGetValue(L"bottom", bottom)); - - const auto expected = !(left < right && top < bottom); - const til::rect actual{ left, top, right, bottom }; - VERIFY_ARE_EQUAL(expected, actual.empty()); - } - TEST_METHOD(ContainsPoint) { BEGIN_TEST_METHOD_PROPERTIES() diff --git a/src/til/ut_til/SizeTests.cpp b/src/til/ut_til/SizeTests.cpp index a75b48922a2..dce512aa1a7 100644 --- a/src/til/ut_til/SizeTests.cpp +++ b/src/til/ut_til/SizeTests.cpp @@ -147,26 +147,20 @@ class SizeTests TEST_METHOD(Boolean) { - const til::size empty; - VERIFY_IS_FALSE(!!empty); + SetVerifyOutput verifyOutputScope{ VerifyOutputSettings::LogOnlyFailures }; - const til::size yOnly{ 0, 10 }; - VERIFY_IS_FALSE(!!yOnly); + static constexpr til::CoordType values[] = { til::CoordTypeMin, -1, 0, 1, til::CoordTypeMax }; - const til::size xOnly{ 10, 0 }; - VERIFY_IS_FALSE(!!xOnly); - - const til::size both{ 10, 10 }; - VERIFY_IS_TRUE(!!both); - - const til::size yNegative{ 10, -10 }; - VERIFY_IS_FALSE(!!yNegative); - - const til::size xNegative{ -10, 10 }; - VERIFY_IS_FALSE(!!xNegative); - - const til::size bothNegative{ -10, -10 }; - VERIFY_IS_FALSE(!!bothNegative); + for (const auto width : values) + { + for (const auto height : values) + { + const til::size s{ width, height }; + const auto expected = width > 0 && height > 0; + const auto actual = static_cast(s); + VERIFY_ARE_EQUAL(expected, actual); + } + } } TEST_METHOD(Addition) diff --git a/src/til/ut_til/SmallVectorTests.cpp b/src/til/ut_til/SmallVectorTests.cpp index f1a2ed88e54..55a338ae86d 100644 --- a/src/til/ut_til/SmallVectorTests.cpp +++ b/src/til/ut_til/SmallVectorTests.cpp @@ -3,8 +3,6 @@ #include "precomp.h" -#include - using namespace std::literals; using namespace WEX::Common; using namespace WEX::Logging; diff --git a/src/til/ut_til/SomeTests.cpp b/src/til/ut_til/SomeTests.cpp deleted file mode 100644 index 98ea25fd64d..00000000000 --- a/src/til/ut_til/SomeTests.cpp +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#include "precomp.h" - -using namespace WEX::Common; -using namespace WEX::Logging; -using namespace WEX::TestExecution; - -class SomeTests -{ - TEST_CLASS(SomeTests); - - TEST_METHOD(Construct) - { - Log::Comment(L"Default Constructor"); - til::some s; - - Log::Comment(L"Valid Initializer List Constructor"); - til::some t{ 1 }; - til::some u{ 1, 2 }; - - Log::Comment(L"Invalid Initializer List Constructor"); - auto f = []() { - til::some v{ 1, 2, 3 }; - }; - - VERIFY_THROWS(f(), std::invalid_argument); - } - - TEST_METHOD(Equality) - { - til::some a{ 1, 2 }; - til::some b{ 1, 2 }; - VERIFY_IS_TRUE(a == b); - - til::some c{ 3, 2 }; - VERIFY_IS_FALSE(a == c); - - til::some d{ 2, 3 }; - VERIFY_IS_FALSE(a == d); - - til::some e{ 1 }; - VERIFY_IS_FALSE(a == e); - } - - TEST_METHOD(Inequality) - { - til::some a{ 1, 2 }; - til::some b{ 1, 2 }; - VERIFY_IS_FALSE(a != b); - - til::some c{ 3, 2 }; - VERIFY_IS_TRUE(a != c); - - til::some d{ 2, 3 }; - VERIFY_IS_TRUE(a != d); - - til::some e{ 1 }; - VERIFY_IS_TRUE(a != e); - } - - TEST_METHOD(Fill) - { - til::some s; - - const auto val = 12; - s.fill(val); - - VERIFY_ARE_EQUAL(s.max_size(), s.size()); - - for (const auto& i : s) - { - VERIFY_ARE_EQUAL(val, i); - } - } - - TEST_METHOD(Swap) - { - til::some a; - til::some b; - - const auto aVal = 900; - a.fill(900); - - const auto bVal = 45; - b.push_back(45); - - const auto aSize = a.size(); - const auto bSize = b.size(); - - a.swap(b); - - VERIFY_ARE_EQUAL(aSize, b.size()); - VERIFY_ARE_EQUAL(bSize, a.size()); - - VERIFY_ARE_EQUAL(bVal, a[0]); - - for (const auto& i : b) - { - VERIFY_ARE_EQUAL(aVal, i); - } - } - - TEST_METHOD(Size) - { - til::some c; - - VERIFY_ARE_EQUAL(0u, c.size()); - - c.push_back(3); - VERIFY_ARE_EQUAL(1u, c.size()); - - c.push_back(12); - VERIFY_ARE_EQUAL(2u, c.size()); - - c.pop_back(); - VERIFY_ARE_EQUAL(1u, c.size()); - - c.pop_back(); - VERIFY_ARE_EQUAL(0u, c.size()); - } - - TEST_METHOD(MaxSize) - { - til::some c; - - VERIFY_ARE_EQUAL(2u, c.max_size()); - - c.push_back(3); - VERIFY_ARE_EQUAL(2u, c.max_size()); - - c.push_back(12); - VERIFY_ARE_EQUAL(2u, c.size()); - - c.pop_back(); - VERIFY_ARE_EQUAL(2u, c.max_size()); - - c.pop_back(); - VERIFY_ARE_EQUAL(2u, c.max_size()); - } - - TEST_METHOD(PushBack) - { - til::some s; - s.push_back(12); - VERIFY_THROWS(s.push_back(12), std::out_of_range); - } - - TEST_METHOD(PopBack) - { - til::some s; - VERIFY_THROWS(s.pop_back(), std::out_of_range); - - s.push_back(12); - VERIFY_THROWS(s.push_back(12), std::out_of_range); - } - - TEST_METHOD(Empty) - { - til::some s; - VERIFY_IS_TRUE(s.empty()); - s.push_back(12); - VERIFY_IS_FALSE(s.empty()); - s.pop_back(); - VERIFY_IS_TRUE(s.empty()); - } - - TEST_METHOD(Clear) - { - til::some s; - VERIFY_IS_TRUE(s.empty()); - s.push_back(12); - VERIFY_IS_FALSE(s.empty()); - VERIFY_ARE_EQUAL(1u, s.size()); - s.clear(); - VERIFY_IS_TRUE(s.empty()); - VERIFY_ARE_EQUAL(0u, s.size()); - } - - TEST_METHOD(ClearFreesMembers) - { - til::some, 2> s; - - auto a = std::make_shared(4); - auto weakA = std::weak_ptr(a); - - auto b = std::make_shared(6); - auto weakB = std::weak_ptr(b); - - s.push_back(std::move(a)); - s.push_back(std::move(b)); - - VERIFY_IS_FALSE(weakA.expired()); - VERIFY_IS_FALSE(weakB.expired()); - - s.clear(); - - VERIFY_IS_TRUE(weakA.expired()); - VERIFY_IS_TRUE(weakB.expired()); - } - - TEST_METHOD(Data) - { - til::some s; - const auto one = 1; - const auto two = 2; - s.push_back(one); - s.push_back(two); - - auto data = s.data(); - - VERIFY_ARE_EQUAL(one, *data); - VERIFY_ARE_EQUAL(two, *(data + 1)); - } - - TEST_METHOD(FrontBack) - { - til::some s; - const auto one = 1; - const auto two = 2; - s.push_back(one); - s.push_back(two); - - VERIFY_ARE_EQUAL(one, s.front()); - VERIFY_ARE_EQUAL(two, s.back()); - } - - TEST_METHOD(Indexing) - { - const auto one = 14; - const auto two = 28; - - til::some s; - VERIFY_THROWS(s.at(0), std::out_of_range); - VERIFY_THROWS(s.at(1), std::out_of_range); - auto a = s[0]; - a = s[1]; - - s.push_back(one); - VERIFY_ARE_EQUAL(one, s.at(0)); - VERIFY_ARE_EQUAL(one, s[0]); - VERIFY_THROWS(s.at(1), std::out_of_range); - a = s[1]; - - s.push_back(two); - VERIFY_ARE_EQUAL(one, s.at(0)); - VERIFY_ARE_EQUAL(one, s[0]); - VERIFY_ARE_EQUAL(two, s.at(1)); - VERIFY_ARE_EQUAL(two, s[1]); - - s.pop_back(); - VERIFY_ARE_EQUAL(one, s.at(0)); - VERIFY_ARE_EQUAL(one, s[0]); - VERIFY_THROWS(s.at(1), std::out_of_range); - a = s[1]; - - s.pop_back(); - VERIFY_THROWS(s.at(0), std::out_of_range); - VERIFY_THROWS(s.at(1), std::out_of_range); - a = s[0]; - a = s[1]; - } - - TEST_METHOD(ForwardIter) - { - const int vals[] = { 17, 99 }; - const int valLength = ARRAYSIZE(vals); - - til::some s; - VERIFY_ARE_EQUAL(s.begin(), s.end()); - VERIFY_ARE_EQUAL(s.cbegin(), s.cend()); - VERIFY_ARE_EQUAL(s.begin(), s.cbegin()); - VERIFY_ARE_EQUAL(s.end(), s.cend()); - - s.push_back(vals[0]); - s.push_back(vals[1]); - - VERIFY_ARE_EQUAL(s.begin() + valLength, s.end()); - VERIFY_ARE_EQUAL(s.cbegin() + valLength, s.cend()); - - auto count = 0; - for (const auto& i : s) - { - VERIFY_ARE_EQUAL(vals[count], i); - ++count; - } - VERIFY_ARE_EQUAL(valLength, count); - - count = 0; - for (auto i = s.cbegin(); i < s.cend(); ++i) - { - VERIFY_ARE_EQUAL(vals[count], *i); - ++count; - } - VERIFY_ARE_EQUAL(valLength, count); - - count = 0; - for (auto i = s.begin(); i < s.end(); ++i) - { - VERIFY_ARE_EQUAL(vals[count], *i); - ++count; - } - VERIFY_ARE_EQUAL(valLength, count); - } - - TEST_METHOD(ReverseIter) - { - const int vals[] = { 17, 99 }; - const int valLength = ARRAYSIZE(vals); - - til::some s; - VERIFY_ARE_EQUAL(s.rbegin(), s.rend()); - VERIFY_ARE_EQUAL(s.crbegin(), s.crend()); - VERIFY_ARE_EQUAL(s.rbegin(), s.crbegin()); - VERIFY_ARE_EQUAL(s.rend(), s.crend()); - - s.push_back(vals[0]); - s.push_back(vals[1]); - - VERIFY_ARE_EQUAL(s.rbegin() + valLength, s.rend()); - VERIFY_ARE_EQUAL(s.crbegin() + valLength, s.crend()); - - auto count = 0; - for (auto i = s.crbegin(); i < s.crend(); ++i) - { - VERIFY_ARE_EQUAL(vals[valLength - count - 1], *i); - ++count; - } - VERIFY_ARE_EQUAL(valLength, count); - - count = 0; - for (auto i = s.rbegin(); i < s.rend(); ++i) - { - VERIFY_ARE_EQUAL(vals[valLength - count - 1], *i); - ++count; - } - VERIFY_ARE_EQUAL(valLength, count); - } -}; diff --git a/src/til/ut_til/UnicodeTests.cpp b/src/til/ut_til/UnicodeTests.cpp index 24d62beeaf6..e81d5b9a7a9 100644 --- a/src/til/ut_til/UnicodeTests.cpp +++ b/src/til/ut_til/UnicodeTests.cpp @@ -51,10 +51,10 @@ class UnicodeTests struct Test { std::wstring_view input; - til::some expected; + std::vector expected; }; - static constexpr std::array tests{ + const std::array tests{ Test{ L"", {} }, Test{ L"a", { L"a" } }, Test{ L"abc", { L"a", L"b", L"c" } }, diff --git a/src/til/ut_til/sources b/src/til/ut_til/sources index ffe976d7cab..2e39e378a84 100644 --- a/src/til/ut_til/sources +++ b/src/til/ut_til/sources @@ -30,7 +30,6 @@ SOURCES = \ RunLengthEncodingTests.cpp \ SizeTests.cpp \ SmallVectorTests.cpp \ - SomeTests.cpp \ StaticMapTests.cpp \ string.cpp \ u8u16convertTests.cpp \ diff --git a/src/til/ut_til/til.unit.tests.vcxproj b/src/til/ut_til/til.unit.tests.vcxproj index 04694e68a16..d6b183d1282 100644 --- a/src/til/ut_til/til.unit.tests.vcxproj +++ b/src/til/ut_til/til.unit.tests.vcxproj @@ -32,7 +32,6 @@ - @@ -64,7 +63,6 @@ - @@ -90,4 +88,4 @@ - \ No newline at end of file + diff --git a/src/til/ut_til/til.unit.tests.vcxproj.filters b/src/til/ut_til/til.unit.tests.vcxproj.filters index c25b0113980..15928ddb533 100644 --- a/src/til/ut_til/til.unit.tests.vcxproj.filters +++ b/src/til/ut_til/til.unit.tests.vcxproj.filters @@ -20,7 +20,6 @@ - @@ -96,9 +95,6 @@ inc - - inc - inc @@ -135,4 +131,4 @@ {7cf29ba4-d33d-4c3b-82e3-ab73e5a79685} - \ No newline at end of file + diff --git a/src/types/inc/IInputEvent.hpp b/src/types/inc/IInputEvent.hpp index 4641c17332d..655acd8f9b7 100644 --- a/src/types/inc/IInputEvent.hpp +++ b/src/types/inc/IInputEvent.hpp @@ -3,8 +3,6 @@ #pragma once -#include - #define ALT_PRESSED (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED) #define CTRL_PRESSED (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED) #define MOD_PRESSED (SHIFT_PRESSED | ALT_PRESSED | CTRL_PRESSED) diff --git a/src/types/inc/viewport.hpp b/src/types/inc/viewport.hpp index d762f64348f..b8b2029504e 100644 --- a/src/types/inc/viewport.hpp +++ b/src/types/inc/viewport.hpp @@ -17,7 +17,7 @@ namespace Microsoft::Console::Types { class Viewport; - using SomeViewports = til::some; + using SomeViewports = til::small_vector; class Viewport final { From 9f3dbab7bf442a1d7702bef0058fa2f0ff5736cd Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Tue, 2 Apr 2024 01:32:31 +0200 Subject: [PATCH 2/9] Fix bugs introduced in #16821 (custom font fallback) (#16993) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Since `FindFontWithLocalizedName` is broken (intentionally and temporarily until #16943 is fixed) we have to be extra be careful not to return a nullptr `Font`. * Portable builds may not have a broken font cache, but also not have the given font (Cascadia Mono for instance) installed. This requires us to load the nearby fonts even if there aren't any exceptions. ## Validation Steps Performed * Open `src/cascadia/CascadiaResources.build.items` and remove the `Condition` for .ttf files * Deploy on a clean Windows 10 VM * Cascadia Mono loads without issues ✅ * Open the `Settings > Defaults > Appearance`, enter a non-existing font and hit Save * Doesn't crash ✅ --- .../TerminalSettingsEditor/Appearances.cpp | 10 +-- .../ProfileViewModel.cpp | 1 + src/renderer/atlas/AtlasEngine.api.cpp | 69 +++++++++++++------ src/renderer/atlas/AtlasEngine.h | 5 +- 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.cpp b/src/cascadia/TerminalSettingsEditor/Appearances.cpp index fe9cabc824f..15417166ad2 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.cpp +++ b/src/cascadia/TerminalSettingsEditor/Appearances.cpp @@ -419,6 +419,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation BOOL hasPowerlineCharacters = FALSE; til::iterate_font_families(fontFace, [&](wil::zwstring_view name) { + if (primaryFontName.empty()) + { + primaryFontName = name; + } + std::wstring* accumulator = nullptr; UINT32 index = 0; @@ -434,11 +439,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation break; } - if (primaryFontName.empty()) - { - primaryFontName = name; - } - wil::com_ptr fontFamily; THROW_IF_FAILED(fontCollection->GetFontFamily(index, fontFamily.addressof())); diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp index a00a077ef5b..d373926b380 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp @@ -187,6 +187,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation UpdateFontList(); } const auto& currentFontList{ CompleteFontList() }; + fallbackFont = currentFontList.First().Current(); for (const auto& font : currentFontList) { if (font.LocalizedName() == name) diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp index c031f67a154..9c98a12cf52 100644 --- a/src/renderer/atlas/AtlasEngine.api.cpp +++ b/src/renderer/atlas/AtlasEngine.api.cpp @@ -482,32 +482,17 @@ void AtlasEngine::SetWarningCallback(std::functionfont->fontCollection` for a pre-existing font collection, - // before falling back to using the system font collection. This way we can inject our custom one. - // Doing it this way is a bit hacky, but it does have the benefit that we can cache a font collection - // instance across font changes, like when zooming the font size rapidly using the scroll wheel. - try + if (FAILED(hr) && _updateWithNearbyFontCollection()) { - _api.s.write()->font.write()->fontCollection = FontCache::GetCached(); + hr = _updateFont(fontInfoDesired, fontInfo, features, axes); } - CATCH_LOG(); } - try - { - _updateFont(fontInfoDesired, fontInfo, features, axes); - return S_OK; - } - CATCH_RETURN(); + return hr; } void AtlasEngine::UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept @@ -536,7 +521,8 @@ void AtlasEngine::_resolveTransparencySettings() noexcept } } -void AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes) +[[nodiscard]] HRESULT AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes) noexcept +try { std::vector fontFeatures; if (!features.empty()) @@ -616,9 +602,12 @@ void AtlasEngine::_updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& _resolveFontMetrics(fontInfoDesired, fontInfo, font); font->fontFeatures = std::move(fontFeatures); font->fontAxisValues = std::move(fontAxisValues); + + return S_OK; } +CATCH_RETURN() -void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics) const +void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics) { const auto& faceName = fontInfoDesired.GetFaceName(); const auto requestedFamily = fontInfoDesired.GetFamily(); @@ -659,6 +648,16 @@ void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, Fo BOOL exists = false; THROW_IF_FAILED(fontCollection->FindFamilyName(fontName.c_str(), &index, &exists)); + // In case of a portable build, the given font may not be installed and instead be bundled next to our executable. + if constexpr (Feature_NearbyFontLoading::IsEnabled()) + { + if (!exists && _updateWithNearbyFontCollection()) + { + fontCollection = _api.s->font->fontCollection; + THROW_IF_FAILED(fontCollection->FindFamilyName(fontName.c_str(), &index, &exists)); + } + } + if (!exists) { if (!missingFontNames.empty()) @@ -869,3 +868,29 @@ void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, Fo fontMetrics->colorGlyphs = fontInfoDesired.GetEnableColorGlyphs(); } } + +// Nearby fonts are described a couple of times throughout the file. +// This abstraction in particular helps us avoid retrying when it's pointless: +// After all, if the font collection didn't change (no nearby fonts, loading failed, it's already loaded), +// we don't need to try it again. It returns true if retrying is necessary. +[[nodiscard]] bool AtlasEngine::_updateWithNearbyFontCollection() noexcept +{ + // _resolveFontMetrics() checks `_api.s->font->fontCollection` for a pre-existing font collection, + // before falling back to using the system font collection. This way we can inject our custom one. + // Doing it this way is a bit hacky, but it does have the benefit that we can cache a font collection + // instance across font changes, like when zooming the font size rapidly using the scroll wheel. + wil::com_ptr collection; + try + { + collection = FontCache::GetCached(); + } + CATCH_LOG(); + + if (!collection || _api.s->font->fontCollection == collection) + { + return false; + } + + _api.s.write()->font.write()->fontCollection = std::move(collection); + return true; +} diff --git a/src/renderer/atlas/AtlasEngine.h b/src/renderer/atlas/AtlasEngine.h index 5c9f954ae2f..6d346d7bfe4 100644 --- a/src/renderer/atlas/AtlasEngine.h +++ b/src/renderer/atlas/AtlasEngine.h @@ -94,8 +94,9 @@ namespace Microsoft::Console::Render::Atlas // AtlasEngine.api.cpp void _resolveTransparencySettings() noexcept; - void _updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes); - void _resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics = nullptr) const; + [[nodiscard]] HRESULT _updateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map& features, const std::unordered_map& axes) noexcept; + void _resolveFontMetrics(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, FontSettings* fontMetrics = nullptr); + [[nodiscard]] bool _updateWithNearbyFontCollection() noexcept; // AtlasEngine.r.cpp ATLAS_ATTR_COLD void _recreateAdapter(); From f2d6cceb2a36827ec3fcb0016e7a604ffdba28c2 Mon Sep 17 00:00:00 2001 From: Windows Console Service Bot <14666831+consvc@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:06:27 -0500 Subject: [PATCH 3/9] Localization Updates - main - 03/30/2024 03:04:37 (#16973) --- src/cascadia/TerminalApp/Resources/de-DE/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/es-ES/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/fr-FR/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/it-IT/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/ja-JP/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/ko-KR/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/pt-BR/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/qps-ploc/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/qps-ploca/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/qps-plocm/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/ru-RU/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/zh-CN/Resources.resw | 6 +++--- src/cascadia/TerminalApp/Resources/zh-TW/Resources.resw | 6 +++--- .../TerminalSettingsEditor/Resources/de-DE/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/es-ES/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/fr-FR/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/it-IT/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/ja-JP/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/ko-KR/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/pt-BR/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/ru-RU/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/zh-CN/Resources.resw | 4 ++++ .../TerminalSettingsEditor/Resources/zh-TW/Resources.resw | 4 ++++ 23 files changed, 79 insertions(+), 39 deletions(-) diff --git a/src/cascadia/TerminalApp/Resources/de-DE/Resources.resw b/src/cascadia/TerminalApp/Resources/de-DE/Resources.resw index f99341de170..948fec8ff61 100644 --- a/src/cascadia/TerminalApp/Resources/de-DE/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/de-DE/Resources.resw @@ -186,9 +186,6 @@ Beenden - - Möchten Sie alle Registerkarten schließen? - Mehrere Bereiche @@ -335,6 +332,9 @@ Mit dem angegebenen Profil öffnen. Akzeptiert entweder den Namen oder die GUID eines Profils + + Legt die WT_SESSION-Variable fest; muss eine GUID sein. + Erstellen eines neuen geteilten Bereichs diff --git a/src/cascadia/TerminalApp/Resources/es-ES/Resources.resw b/src/cascadia/TerminalApp/Resources/es-ES/Resources.resw index 7eaf5023fd7..0679cd0ddd6 100644 --- a/src/cascadia/TerminalApp/Resources/es-ES/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/es-ES/Resources.resw @@ -183,9 +183,6 @@ Salir - - ¿Quieres cerrar todas las pestañas? - Varios paneles @@ -332,6 +329,9 @@ Abre con el perfil determinado. Acepta el nombre o el GUID de un perfil. + + Establece la variable WT_SESSION; debe ser un GUID + Crear un nuevo panel de división diff --git a/src/cascadia/TerminalApp/Resources/fr-FR/Resources.resw b/src/cascadia/TerminalApp/Resources/fr-FR/Resources.resw index 3f5a403a79a..887f79be427 100644 --- a/src/cascadia/TerminalApp/Resources/fr-FR/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/fr-FR/Resources.resw @@ -183,9 +183,6 @@ Quitter - - Voulez-vous fermer tous les onglets ? - Volets multiples @@ -332,6 +329,9 @@ Ouvrez avec le profil donné. Accepte le nom ou le GUID d’un profil + + Définit la variable WT_SESSION ; doit être un GUID + Créer un volet de fractionnement diff --git a/src/cascadia/TerminalApp/Resources/it-IT/Resources.resw b/src/cascadia/TerminalApp/Resources/it-IT/Resources.resw index fb7b04cd57d..69122195dbb 100644 --- a/src/cascadia/TerminalApp/Resources/it-IT/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/it-IT/Resources.resw @@ -183,9 +183,6 @@ Esci - - Vuoi chiudere tutte le schede? - Più riquadri @@ -332,6 +329,9 @@ Apri con il profilo specificato. Accetta il nome oppure il GUID di un profilo + + Imposta la variabile di WT_SESSION; deve essere un GUID + Crea un nuovo riquadro suddiviso diff --git a/src/cascadia/TerminalApp/Resources/ja-JP/Resources.resw b/src/cascadia/TerminalApp/Resources/ja-JP/Resources.resw index 48db8a0fd68..3451318e931 100644 --- a/src/cascadia/TerminalApp/Resources/ja-JP/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/ja-JP/Resources.resw @@ -184,9 +184,6 @@ 終了 - - すべてのタブを閉じますか? - 複数ウィンドウ @@ -333,6 +330,9 @@ 指定されたプロファイルで開きます。プロファイルの名前または GUID を指定できます + + WT_SESSION 変数を設定します; GUID である必要があります + 新しい分割ウィンドウの作成 diff --git a/src/cascadia/TerminalApp/Resources/ko-KR/Resources.resw b/src/cascadia/TerminalApp/Resources/ko-KR/Resources.resw index 820db0c8fed..2b7ebd75146 100644 --- a/src/cascadia/TerminalApp/Resources/ko-KR/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/ko-KR/Resources.resw @@ -183,9 +183,6 @@ 끝내기 - - 모든 탭을 닫으시겠습니까? - 여러 창 @@ -332,6 +329,9 @@ 지정된 프로필로 엽니다. 프로필 이름 또는 GUID 허용 + + WT_SESSION 변수를 설정합니다. GUID여야 합니다. + 새 분할 창 만들기 diff --git a/src/cascadia/TerminalApp/Resources/pt-BR/Resources.resw b/src/cascadia/TerminalApp/Resources/pt-BR/Resources.resw index 2ba06ec576d..d94a2946410 100644 --- a/src/cascadia/TerminalApp/Resources/pt-BR/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/pt-BR/Resources.resw @@ -183,9 +183,6 @@ Encerrar - - Deseja fechar todas as guias? - Vários painéis @@ -332,6 +329,9 @@ Abrir com o perfil determinado. Aceite o nome ou o GUID de um perfil + + Define a variável WT_SESSION; deve ser um GUID + Criar um novo painel dividido diff --git a/src/cascadia/TerminalApp/Resources/qps-ploc/Resources.resw b/src/cascadia/TerminalApp/Resources/qps-ploc/Resources.resw index 206c42a94b4..0e553d2fc36 100644 --- a/src/cascadia/TerminalApp/Resources/qps-ploc/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/qps-ploc/Resources.resw @@ -187,9 +187,6 @@ Qùíт ! - - Đǿ ÿõű ŵãŋт тŏ ¢ľòŝê ăŀľ ŧãвŝ? !!! !!! !!! - Мµļтíрłĕ φдпėŝ !!! ! @@ -340,6 +337,9 @@ Θφêп шĩτћ ťнě ģìνēή ρѓøƒìĺę. Âćĉеφťś ёĩτĥėŗ τђė йάмє øя ĠŮΪÐ õƒ а φŕóƒίℓè !!! !!! !!! !!! !!! !!! !!! + + Šέŧś ŧћэ ẀŦ_ŜÉŜŜІΟΝ νăяíåьłé; mµśτ вэ â ĢŨÎĐ !!! !!! !!! !!! ! + Ĉґéáŧе д ήэẅ ŝφĺĭτ рãňё !!! !!! diff --git a/src/cascadia/TerminalApp/Resources/qps-ploca/Resources.resw b/src/cascadia/TerminalApp/Resources/qps-ploca/Resources.resw index 206c42a94b4..0e553d2fc36 100644 --- a/src/cascadia/TerminalApp/Resources/qps-ploca/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/qps-ploca/Resources.resw @@ -187,9 +187,6 @@ Qùíт ! - - Đǿ ÿõű ŵãŋт тŏ ¢ľòŝê ăŀľ ŧãвŝ? !!! !!! !!! - Мµļтíрłĕ φдпėŝ !!! ! @@ -340,6 +337,9 @@ Θφêп шĩτћ ťнě ģìνēή ρѓøƒìĺę. Âćĉеφťś ёĩτĥėŗ τђė йάмє øя ĠŮΪÐ õƒ а φŕóƒίℓè !!! !!! !!! !!! !!! !!! !!! + + Šέŧś ŧћэ ẀŦ_ŜÉŜŜІΟΝ νăяíåьłé; mµśτ вэ â ĢŨÎĐ !!! !!! !!! !!! ! + Ĉґéáŧе д ήэẅ ŝφĺĭτ рãňё !!! !!! diff --git a/src/cascadia/TerminalApp/Resources/qps-plocm/Resources.resw b/src/cascadia/TerminalApp/Resources/qps-plocm/Resources.resw index 206c42a94b4..0e553d2fc36 100644 --- a/src/cascadia/TerminalApp/Resources/qps-plocm/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/qps-plocm/Resources.resw @@ -187,9 +187,6 @@ Qùíт ! - - Đǿ ÿõű ŵãŋт тŏ ¢ľòŝê ăŀľ ŧãвŝ? !!! !!! !!! - Мµļтíрłĕ φдпėŝ !!! ! @@ -340,6 +337,9 @@ Θφêп шĩτћ ťнě ģìνēή ρѓøƒìĺę. Âćĉеφťś ёĩτĥėŗ τђė йάмє øя ĠŮΪÐ õƒ а φŕóƒίℓè !!! !!! !!! !!! !!! !!! !!! + + Šέŧś ŧћэ ẀŦ_ŜÉŜŜІΟΝ νăяíåьłé; mµśτ вэ â ĢŨÎĐ !!! !!! !!! !!! ! + Ĉґéáŧе д ήэẅ ŝφĺĭτ рãňё !!! !!! diff --git a/src/cascadia/TerminalApp/Resources/ru-RU/Resources.resw b/src/cascadia/TerminalApp/Resources/ru-RU/Resources.resw index a66c47aabd6..0a74add4c32 100644 --- a/src/cascadia/TerminalApp/Resources/ru-RU/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/ru-RU/Resources.resw @@ -183,9 +183,6 @@ Выход - - Закрыть все вкладки? - Несколько областей @@ -332,6 +329,9 @@ Открыть с помощью данного профиля. Принимается имя или GUID профиля + + Задает переменную WT_SESSION; должно быть GUID + Создать новую область разделения diff --git a/src/cascadia/TerminalApp/Resources/zh-CN/Resources.resw b/src/cascadia/TerminalApp/Resources/zh-CN/Resources.resw index 7cee543bce9..78135ba31a8 100644 --- a/src/cascadia/TerminalApp/Resources/zh-CN/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/zh-CN/Resources.resw @@ -183,9 +183,6 @@ 退出 - - 是否要关闭所有标签页? - 多个窗格 @@ -332,6 +329,9 @@ 使用给定的配置文件打开。接受配置文件的名称或 GUID + + 设置 WT_SESSION 变量;必须是 GUID + 创建新的拆分窗格 diff --git a/src/cascadia/TerminalApp/Resources/zh-TW/Resources.resw b/src/cascadia/TerminalApp/Resources/zh-TW/Resources.resw index 33e548f77ad..5a7e89a6711 100644 --- a/src/cascadia/TerminalApp/Resources/zh-TW/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/zh-TW/Resources.resw @@ -183,9 +183,6 @@ 結束 - - 您要關閉所有索引標籤嗎? - 多個窗格 @@ -332,6 +329,9 @@ 使用指定的設定檔開啟。接受設定檔的名稱或 GUID + + 設定 WT_SESSION 變數; 必須為 GUID + 建立新的分割窗格 diff --git a/src/cascadia/TerminalSettingsEditor/Resources/de-DE/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/de-DE/Resources.resw index 96d50e58db8..eb3aee0ac6e 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/de-DE/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/de-DE/Resources.resw @@ -989,6 +989,10 @@ Dieses Profil als Administrator ausführen Header for a control to toggle whether the profile should always open elevated (in an admin window) + + Wenn diese Option aktiviert ist, wird das Profil automatisch in einem Admin Terminalfenster geöffnet. Wenn das aktuelle Fenster bereits als Administrator ausgeführt wird, wird es in diesem Fenster geöffnet. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + Größe des Verlaufs Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/es-ES/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/es-ES/Resources.resw index db4abb81b4f..06ef4c0b3c2 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/es-ES/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/es-ES/Resources.resw @@ -989,6 +989,10 @@ Ejecutar este perfil como Administrador Header for a control to toggle whether the profile should always open elevated (in an admin window) + + Si se habilita, el perfil se abrirá automáticamente en una ventana de terminal Administración. Si la ventana actual ya se está ejecutando como administrador, se abrirá en esta ventana. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + Tamaño del historial Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/fr-FR/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/fr-FR/Resources.resw index f14f47e5848..0d2433ba1de 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/fr-FR/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/fr-FR/Resources.resw @@ -989,6 +989,10 @@ Exécuter ce profil en tant qu’administrateur Header for a control to toggle whether the profile should always open elevated (in an admin window) + + Si cette option est activée, le profil s’ouvre automatiquement dans une fenêtre de terminal Administration. Si la fenêtre active est déjà en cours d’exécution en tant qu’administrateur, elle s’ouvre dans cette fenêtre. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + Taille de l’historique Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/it-IT/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/it-IT/Resources.resw index 5bb075b01f9..6cbfe190b22 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/it-IT/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/it-IT/Resources.resw @@ -989,6 +989,10 @@ Esegui questo profilo come amministratore Header for a control to toggle whether the profile should always open elevated (in an admin window) + + Se questa opzione è abilitata, il profilo verrà aperto automaticamente in una finestra del terminale Amministrazione. Se la finestra corrente è già in esecuzione come amministratore, verrà aperta in questa finestra. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + Dimensioni cronologia Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/ja-JP/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/ja-JP/Resources.resw index e9f4b3eb2f2..70e4da642b0 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/ja-JP/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/ja-JP/Resources.resw @@ -989,6 +989,10 @@ このプロファイルを管理者として実行する Header for a control to toggle whether the profile should always open elevated (in an admin window) + + 有効にすると、プロファイルは自動的にターミナル ウィンドウ管理開きます。現在のウィンドウが既に管理者として実行されている場合は、このウィンドウで開きます。 + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + 履歴のサイズ Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/ko-KR/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/ko-KR/Resources.resw index 7e4a769c59b..04bf3054043 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/ko-KR/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/ko-KR/Resources.resw @@ -989,6 +989,10 @@ 이 프로필을 관리자 권한으로 실행 Header for a control to toggle whether the profile should always open elevated (in an admin window) + + 사용하도록 설정하면 프로필이 관리 터미널 창에서 자동으로 열립니다. 현재 창이 관리자 권한으로 이미 실행되고 있는 경우 이 창에서 열립니다. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + 기록 크기 Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/pt-BR/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/pt-BR/Resources.resw index 8352f42f0da..09611a80f06 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/pt-BR/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/pt-BR/Resources.resw @@ -989,6 +989,10 @@ Executar esse perfil como Administrador Header for a control to toggle whether the profile should always open elevated (in an admin window) + + Se habilitado, o perfil será aberto em uma janela Administração terminal automaticamente. Se a janela atual já estiver em execução como administrador, ela será aberta nesta janela. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + Tamanho de histórico Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/ru-RU/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/ru-RU/Resources.resw index 5d8bb846c6e..4c18e988ea3 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/ru-RU/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/ru-RU/Resources.resw @@ -989,6 +989,10 @@ Запустить этот профиль от имени администратора Header for a control to toggle whether the profile should always open elevated (in an admin window) + + Если этот параметр включен, профиль будет автоматически открываться в Администратор терминала. Если текущее окно уже запущено от имени администратора, оно откроется в этом окне. + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + Размер журнала Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/zh-CN/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/zh-CN/Resources.resw index 7dcaa741b32..1dfc634ae45 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/zh-CN/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/zh-CN/Resources.resw @@ -989,6 +989,10 @@ 以管理员身份运行此配置文件 Header for a control to toggle whether the profile should always open elevated (in an admin window) + + 如果启用,配置文件将在管理员终端窗口中自动打开。如果当前窗口已以管理员身份运行,它将在此窗口中打开。 + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + 历史记录大小 Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. diff --git a/src/cascadia/TerminalSettingsEditor/Resources/zh-TW/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/zh-TW/Resources.resw index 2f1cf24cb98..ccc0bb47203 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/zh-TW/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/zh-TW/Resources.resw @@ -989,6 +989,10 @@ 以系統管理員身分執行此設定檔 Header for a control to toggle whether the profile should always open elevated (in an admin window) + + 如果啟用,配置檔將會自動在 管理員 終端機視窗中開啟。如果目前的視窗已以系統管理員身分執行,則會在此視窗中開啟。 + A description for what the "elevate" setting does. Presented near "Profile_Elevate". + 歷史大小 Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session. From ad0b67239da6031551146ee93e7d526cb0a01c4d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 2 Apr 2024 10:07:33 -0700 Subject: [PATCH 4/9] Add some docs on how to resolve `DEP0700` errors in VS (#16997) This happens to me once a month, and I finally solved it. --- doc/building.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/doc/building.md b/doc/building.md index 968a6abd8db..60f53343937 100644 --- a/doc/building.md +++ b/doc/building.md @@ -154,3 +154,47 @@ popd The `bx` will build just the Terminal package, critically, populating the `CascadiaPackage.build.appxrecipe` file. Once that's been built, then the `DeployAppRecipe.exe` command can be used to deploy a loose layout in the same way that Visual Studio does. Notably, this method of building the Terminal package can't leverage the FastUpToDate check in Visual Studio, so the builds end up being considerably slower for the whole package, as cppwinrt does a lot of work before confirming that it's up to date and doing nothing. + + +### Are you seeing `DEP0700: Registration of the app failed`? + +Once in a blue moon, I get a `DEP0700: Registration of the app failed. +[0x80073CF6] error 0x80070020: Windows cannot register the package because of an +internal error or low memory.` when trying to deploy in VS. For us, that can +happen if the `OpenConsoleProxy.dll` gets locked up, in use by some other +terminal package. + +Doing the equivalent command in powershell can give us more info: + +```pwsh +Add-AppxPackage -register "Z:\dev\public\OpenConsole\src\cascadia\CascadiaPackage\bin\x64\Debug\AppX\AppxManifest.xml" +``` + +That'll suggest `NOTE: For additional information, look for [ActivityId] +dbf551f1-83d0-0007-43e7-9cded083da01 in the Event Log or use the command line +Get-AppPackageLog -ActivityID dbf551f1-83d0-0007-43e7-9cded083da01`. So do that: + +```pwsh +Get-AppPackageLog -ActivityID dbf551f1-83d0-0007-43e7-9cded083da01 +``` + +which will give you a lot of info. In my case, that revealed that the platform +couldn't delete the packaged com entries. The key line was: `AppX Deployment +operation failed with error 0x0 from API Logging data because access was denied +for file: +C:\ProgramData\Microsoft\Windows\AppRepository\Packages\WindowsTerminalDev_0.0.1.0_x64__8wekyb3d8bbwe, +user SID: S-1-5-18` + +Take that path, and +```pwsh +sudo start C:\ProgramData\Microsoft\Windows\AppRepository\Packages\WindowsTerminalDev_0.0.1.0_x64__8wekyb3d8bbwe +``` + +(use `sudo`, since the path is otherwise locked down). From there, go into the +`PackagedCom` folder, and open [File +Locksmith](https://learn.microsoft.com/en-us/windows/powertoys/file-locksmith) +(or Process Explorer, if you're more familiar with that) on +`OpenConsoleProxy.dll`. Just go ahead and immediately re-launch it as admin, +too. That should list off a couple terminal processes that are just hanging +around. Go ahead and end them all. You should be good to deploy again after +that. From 5f1015953fc65c5542a338de778cbc9acaf01faf Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 2 Apr 2024 10:08:03 -0700 Subject: [PATCH 5/9] Don't explode on session restore (#16998) As noted in #16995. Don't persist us if we weren't ever initialized. In that case, we never got an initial size, never instantiated a buffer, and didn't start the connection yet, so there's nothing for us to add here. If we were supposed to be restored from a path, then we don't need to do anything special here. We'll leave the original file untouched, and the next time we actually are initialized, we'll just use that file then. Closes #16995 --- src/cascadia/TerminalControl/TermControl.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp index 0e459e9238b..ec9807dcd08 100644 --- a/src/cascadia/TerminalControl/TermControl.cpp +++ b/src/cascadia/TerminalControl/TermControl.cpp @@ -2276,7 +2276,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation void TermControl::PersistToPath(const winrt::hstring& path) const { - winrt::get_self(_core)->PersistToPath(path.c_str()); + // Don't persist us if we weren't ever initialized. In that case, we + // never got an initial size, never instantiated a buffer, and didn't + // start the connection yet, so there's nothing for us to add here. + // + // If we were supposed to be restored from a path, then we don't need to + // do anything special here. We'll leave the original file untouched, + // and the next time we actually are initialized, we'll just use that + // file then. + if (_initializedTerminal) + { + winrt::get_self(_core)->PersistToPath(path.c_str()); + } } void TermControl::Close() From ad0c28b30ddf36e1719bae5e1ef92f085594e19c Mon Sep 17 00:00:00 2001 From: Marcel W Date: Tue, 2 Apr 2024 19:56:26 +0200 Subject: [PATCH 6/9] Add clamping of initial rows and columns settings (#16989) This clamps the initial rows and columns settings in two areas: - When reading the JSON file - In the settings dialogue For consistency, I've also added a minimum value to the NumberBoxes even though the default Minimum is 1. The Maximum and Minimum are taken from the JSON Schema file (Min 1, Max 999). Closes #11957 --------- Co-authored-by: Dustin L. Howett --- src/cascadia/TerminalSettingsEditor/Launch.xaml | 4 ++++ .../TerminalSettingsModel/GlobalAppSettings.cpp | 11 +++++++++++ .../DeserializationTests.cpp | 15 +++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/cascadia/TerminalSettingsEditor/Launch.xaml b/src/cascadia/TerminalSettingsEditor/Launch.xaml index e68076a5032..2498662a4ce 100644 --- a/src/cascadia/TerminalSettingsEditor/Launch.xaml +++ b/src/cascadia/TerminalSettingsEditor/Launch.xaml @@ -184,6 +184,8 @@ Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" + Maximum="999" + Minimum="1" Style="{StaticResource LaunchSizeNumberBoxStyle}" Value="{x:Bind ViewModel.InitialCols, Mode=TwoWay}" /> diff --git a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp index c307050a998..ff6dd5eec63 100644 --- a/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp @@ -137,6 +137,17 @@ void GlobalAppSettings::LayerJson(const Json::Value& json, const OriginTag origi MTSM_GLOBAL_SETTINGS(GLOBAL_SETTINGS_LAYER_JSON) #undef GLOBAL_SETTINGS_LAYER_JSON + // GH#11975 We only want to allow sensible values and prevent crashes, so we are clamping those values + // We only want to assign if the value did change through clamping, + // otherwise we could end up setting defaults that get persisted + if (this->HasInitialCols()) + { + this->InitialCols(std::clamp(this->InitialCols(), 1, 999)); + } + if (this->HasInitialRows()) + { + this->InitialRows(std::clamp(this->InitialRows(), 1, 999)); + } LayerActionsFrom(json, origin, true); JsonUtils::GetValueForKey(json, LegacyReloadEnvironmentVariablesKey, _legacyReloadEnvironmentVariables); diff --git a/src/cascadia/UnitTests_SettingsModel/DeserializationTests.cpp b/src/cascadia/UnitTests_SettingsModel/DeserializationTests.cpp index 2425e3421d8..bd17076bc94 100644 --- a/src/cascadia/UnitTests_SettingsModel/DeserializationTests.cpp +++ b/src/cascadia/UnitTests_SettingsModel/DeserializationTests.cpp @@ -47,6 +47,7 @@ namespace SettingsModelUnitTests TEST_METHOD(ValidateKeybindingsWarnings); TEST_METHOD(ValidateColorSchemeInCommands); TEST_METHOD(ValidateExecuteCommandlineWarning); + TEST_METHOD(TestClampingOfStartupColumnAndViewProperties); TEST_METHOD(TestTrailingCommas); TEST_METHOD(TestCommandsAndKeybindings); TEST_METHOD(TestNestedCommandWithoutName); @@ -1301,6 +1302,20 @@ namespace SettingsModelUnitTests VERIFY_ARE_EQUAL(SettingsLoadWarnings::MissingRequiredParameter, settings->Warnings().GetAt(3)); } + void DeserializationTests::TestClampingOfStartupColumnAndViewProperties() + { + static constexpr std::string_view inputSettings{ R"({ + "initialCols" : 1000000, + "initialRows" : -1000000, + "profiles": [{ "name": "profile0" }] + })" }; + + const auto settings = createSettings(inputSettings); + + VERIFY_ARE_EQUAL(999, settings->GlobalSettings().InitialCols()); + VERIFY_ARE_EQUAL(1, settings->GlobalSettings().InitialRows()); + } + void DeserializationTests::TestTrailingCommas() { static constexpr std::string_view badSettings{ R"({ From 4d58137bd4ce0dc3563d4991f1cb6ff1115f25cb Mon Sep 17 00:00:00 2001 From: Tushar Singh Date: Wed, 3 Apr 2024 01:27:19 +0530 Subject: [PATCH 7/9] Fix selection expansion for Double-Width and Double-Height rows (#16812) Closes #16782 ### Validation Steps Performed - Double-clicking on a Double-Width row selects the word (identified by delimiters) under the cursor. - Tripple-clicking on a Double-Width row selects the whole line under the cursor. - The same works for Double-Height rows also. - The same works for Single-Width rows also. --- src/buffer/out/textBuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index 40cfc6b17ad..75cd6fd4f01 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -1297,7 +1297,8 @@ void TextBuffer::TriggerNewTextNotification(const std::wstring_view newText) // - the delimiter class for the given char DelimiterClass TextBuffer::_GetDelimiterClassAt(const til::point pos, const std::wstring_view wordDelimiters) const { - return GetRowByOffset(pos.y).DelimiterClassAt(pos.x, wordDelimiters); + const auto realPos = ScreenToBufferPosition(pos); + return GetRowByOffset(realPos.y).DelimiterClassAt(realPos.x, wordDelimiters); } // Method Description: From 04fa18de71a23a1ec66c5e968a8bd96c2e654f4c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 2 Apr 2024 13:27:43 -0700 Subject: [PATCH 8/9] Scratch tool: generate a fragment extension with every color scheme (#16962) #16953 got me thinking: what if we just published an extension ourselves that just packages up every color scheme in the ever-amazing https://github.com/mbadolato/iTerm2-Color-Schemes? Well, this isn't a package for that file. But it is a script to generate a fragment with all of them, and blat it into your `%LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments`. It's a notebook because I've been really fascinated with the Polyglot Notebooks recently. --- .../schemes-fragment/import-all-schemes.ipynb | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/tools/schemes-fragment/import-all-schemes.ipynb diff --git a/src/tools/schemes-fragment/import-all-schemes.ipynb b/src/tools/schemes-fragment/import-all-schemes.ipynb new file mode 100644 index 00000000000..c387d28b6b8 --- /dev/null +++ b/src/tools/schemes-fragment/import-all-schemes.ipynb @@ -0,0 +1,147 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ITerm2 schemes for the Terminal\n", + "\n", + "This is a little helper script to gather up all the color schemes in [mbadolato/iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes), and put them in a single fragment extension for the Terminal. \n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "polyglot_notebook": { + "kernelName": "pwsh" + } + }, + "outputs": [], + "source": [ + "# Clone the repo into the temp directory\n", + "\n", + "cd \"$env:TEMP\"\n", + "if (Test-Path -Path \"$env:TEMP\\iTerm2-Color-Schemes\") {\n", + " Remove-Item -Recurse -Force \"$env:TEMP\\iTerm2-Color-Schemes\"\n", + "}\n", + "git clone --depth 1 https://github.com/mbadolato/iTerm2-Color-Schemes.git\n", + "\n", + "cd \"$env:TEMP\\iTerm2-Color-Schemes\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "polyglot_notebook": { + "kernelName": "pwsh" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Importing schemes from 'C:\\Users\\migrie\\AppData\\Local\\Temp\\iTerm2-Color-Schemes'\n", + "Found 319 schemes\n", + "\u001b[K Importing C:\\Users\\migrie\\AppData\\Local\\Temp\\iTerm2-Color-Schemes\\windowsterminal\\zenwritten_light.json Imported json for 319 schemes\n", + "\n", + " Directory: C:\\Users\\migrie\\AppData\\Local\\Microsoft\\Windows Terminal\\Fragments\n", + "\n", + "\u001b[32;1mMode \u001b[0m\u001b[32;1m LastWriteTime\u001b[0m \u001b[32;1;3m Length\u001b[0m\u001b[32;1m Name\u001b[0m\n", + "\u001b[32;1m---- \u001b[0m \u001b[32;1m -------------\u001b[0m \u001b[32;1m ------\u001b[0m \u001b[32;1m----\u001b[0m\n", + "d---- 3/28/2024 6:30 AM \u001b[44;1mAllColorSchemes\u001b[0m\n", + "Fragment json written to C:\\Users\\migrie\\AppData\\Local\\Microsoft\\Windows Terminal\\Fragments\\AllColorSchemes\\schemes.json\n", + "\n" + ] + } + ], + "source": [ + "cd \"$env:TEMP\\iTerm2-Color-Schemes\"\n", + "\n", + "Write-Host \"Importing schemes from '$env:TEMP\\iTerm2-Color-Schemes'\"\n", + "\n", + "# Iterate over all the files in the `windowsterminal` directory\n", + "\n", + "$allSchemesFiles = Get-ChildItem -Path \"$env:TEMP\\iTerm2-Color-Schemes\\windowsterminal\" -Filter *.json\n", + "Write-host \"Found $($allSchemesFiles.Count) schemes\"\n", + "\n", + "$allSchemeJsons = @()\n", + "\n", + "$allSchemesFiles | ForEach-Object {\n", + "\n", + " Write-Host \"`r`e[K Importing $_ \" -NoNewline\n", + " $json = Get-Content $_.FullName -Raw | ConvertFrom-Json\n", + " $allSchemeJsons += $json\n", + "\n", + "}\n", + "Write-Host \"\"\n", + "Write-Host \"Imported json for $($allSchemeJsons.Count) schemes\"\n", + "\n", + "# Create a new fragment json in the temp directory with all the schemes added to a \"schemes\" array\n", + "\n", + "$fragmentJson = @{\n", + " \"schemes\" = $allSchemeJsons\n", + "} | ConvertTo-Json\n", + "\n", + "# Remove the existing fragment json if it exists\n", + "$fragmentDir = $env:LOCALAPPDATA + \"\\Microsoft\\Windows Terminal\\Fragments\\AllColorSchemes\"\n", + "$fragmentPath = $fragmentDir + \"\\schemes.json\"\n", + "if (Test-Path -Path $fragmentPath) {\n", + " Remove-Item -Path $fragmentPath\n", + "}\n", + "# make sure the directory exists\n", + "New-Item -Path $fragmentDir -ItemType Directory -Force\n", + "\n", + "# Write the fragment json to the fragments directory\n", + "Write-Output $fragmentJson | Out-File $fragmentPath -Encoding Utf8\n", + "\n", + "write-host \"Fragment json written to $fragmentPath\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After running this notebook, all the color schemes will be available in the Terminal. You'll probably need to go touch the settings to get them reloaded. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (C#)", + "language": "C#", + "name": ".net-csharp" + }, + "language_info": { + "name": "polyglot-notebook" + }, + "polyglot_notebook": { + "kernelInfo": { + "defaultKernelName": "csharp", + "items": [ + { + "aliases": [], + "name": "csharp" + }, + { + "aliases": [], + "languageName": "pwsh", + "name": "pwsh" + } + ] + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 2bcbe6b49208cb2040091b1cd2c9b3df8e69f5bd Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Tue, 2 Apr 2024 17:52:29 -0500 Subject: [PATCH 9/9] ci/rel: publish symbols using the internal symbol request API instead (#16991) Work is ongoing to remove individually-authenticated service accounts from some pipelines. This moves us closer to that goal. Tested in Nightly 2403.28002. --- .github/actions/spelling/allow/microsoft.txt | 2 + build/pipelines/ob-nightly.yml | 2 + build/pipelines/ob-release.yml | 2 + ...sh-symbols-using-symbolrequestprod-api.yml | 117 ++++++++++++++++++ .../pipeline-onebranch-full-release-build.yml | 9 +- 5 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml diff --git a/.github/actions/spelling/allow/microsoft.txt b/.github/actions/spelling/allow/microsoft.txt index 5e7aa5c06ee..9cda69aa947 100644 --- a/.github/actions/spelling/allow/microsoft.txt +++ b/.github/actions/spelling/allow/microsoft.txt @@ -32,6 +32,7 @@ DWINRT enablewttlogging HOMESHARE Intelli +issecret IVisual libucrt libucrtd @@ -74,6 +75,7 @@ sid Skype SRW sxs +symbolrequestprod Sysinternals sysnative systemroot diff --git a/build/pipelines/ob-nightly.yml b/build/pipelines/ob-nightly.yml index 1c90866f9e2..99cff5b206c 100644 --- a/build/pipelines/ob-nightly.yml +++ b/build/pipelines/ob-nightly.yml @@ -33,6 +33,8 @@ extends: publishSymbolsToPublic: true publishVpackToWindows: false symbolExpiryTime: 15 + symbolPublishingSubscription: $(SymbolPublishingServiceConnection) + symbolPublishingProject: $(SymbolPublishingProject) ${{ if eq(true, parameters.publishToAzure) }}: extraPublishJobs: - template: build/pipelines/templates-v2/job-deploy-to-azure-storage.yml@self diff --git a/build/pipelines/ob-release.yml b/build/pipelines/ob-release.yml index ca168e6d337..147fef4e5a1 100644 --- a/build/pipelines/ob-release.yml +++ b/build/pipelines/ob-release.yml @@ -81,3 +81,5 @@ extends: terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }} publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }} publishVpackToWindows: ${{ parameters.publishVpackToWindows }} + symbolPublishingSubscription: $(SymbolPublishingServiceConnection) + symbolPublishingProject: $(SymbolPublishingProject) diff --git a/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml b/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml new file mode 100644 index 00000000000..0f9d338699b --- /dev/null +++ b/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml @@ -0,0 +1,117 @@ +parameters: + - name: includePublicSymbolServer + type: boolean + default: false + - name: pool + type: object + default: [] + - name: dependsOn + type: object + default: null + - name: artifactStem + type: string + default: '' + - name: jobName + type: string + default: PublishSymbols + - name: symbolExpiryTime + type: string + default: 36530 # This is the default from PublishSymbols@2 + - name: variables + type: object + default: {} + - name: subscription + type: string + - name: symbolProject + type: string + +jobs: +- job: ${{ parameters.jobName }} + ${{ if ne(length(parameters.pool), 0) }}: + pool: ${{ parameters.pool }} + ${{ if eq(parameters.includePublicSymbolServer, true) }}: + displayName: Publish Symbols to Internal and MSDL + ${{ else }}: + displayName: Publish Symbols Internally + dependsOn: ${{ parameters.dependsOn }} + variables: + ${{ insert }}: ${{ parameters.variables }} + steps: + - checkout: self + clean: true + fetchDepth: 1 + fetchTags: false # Tags still result in depth > 1 fetch; we don't need them here + submodules: true + persistCredentials: True + + - task: PkgESSetupBuild@12 + displayName: Package ES - Setup Build + inputs: + disableOutputRedirect: true + + - task: DownloadPipelineArtifact@2 + displayName: Download all PDBs from all prior build phases + inputs: + itemPattern: '**/*.pdb' + targetPath: '$(Build.SourcesDirectory)/bin' + + - powershell: |- + Get-PackageProvider -Name NuGet -ForceBootstrap + Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute + displayName: Install Azure Module Dependencies + + # Transit the Azure token from the Service Connection into a secret variable for the rest of the pipeline to use. + - task: AzurePowerShell@5 + displayName: Generate an Azure Token + inputs: + azureSubscription: ${{ parameters.subscription }} + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptType: InlineScript + Inline: |- + $AzToken = (Get-AzAccessToken -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token + Write-Host "##vso[task.setvariable variable=SymbolAccessToken;issecret=true]$AzToken" + + + - task: PublishSymbols@2 + displayName: Publish Symbols (to current Azure DevOps tenant) + continueOnError: True + inputs: + SymbolsFolder: '$(Build.SourcesDirectory)/bin' + SearchPattern: '**/*.pdb' + IndexSources: false + DetailedLog: true + SymbolsMaximumWaitTime: 30 + SymbolServerType: 'TeamServices' + SymbolsProduct: 'Windows Terminal Converged Symbols' + SymbolsVersion: '$(XES_APPXMANIFESTVERSION)' + SymbolsArtifactName: 'WindowsTerminal_$(XES_APPXMANIFESTVERSION)' + SymbolExpirationInDays: ${{ parameters.symbolExpiryTime }} + env: + LIB: $(Build.SourcesDirectory) + + - pwsh: |- + # Prepare the defaults for IRM + $PSDefaultParameterValues['Invoke-RestMethod:Headers'] = @{ Authorization = "Bearer $(SymbolAccessToken)" } + $PSDefaultParameterValues['Invoke-RestMethod:ContentType'] = "application/json" + $PSDefaultParameterValues['Invoke-RestMethod:Method'] = "POST" + + $BaseUri = "https://symbolrequestprod.trafficmanager.net/projects/${{ parameters.symbolProject }}/requests" + + # Prepare the request + $expiration = (Get-Date).Add([TimeSpan]::FromDays(${{ parameters.symbolExpiryTime }})) + $createRequestBody = @{ + requestName = "WindowsTerminal_$(XES_APPXMANIFESTVERSION)"; + expirationTime = $expiration.ToString(); + } + Write-Host "##[debug]Starting request $($createRequestBody.requestName) with expiration date of $($createRequestBody.expirationTime)" + Invoke-RestMethod -Uri "$BaseUri" -Body ($createRequestBody | ConvertTo-Json -Compress) -Verbose + + # Request symbol publication + $publishRequestBody = @{ + publishToInternalServer = $true; + publishToPublicServer = $${{ parameters.includePublicSymbolServer }}; + } + Write-Host "##[debug]Submitting request $($createRequestBody.requestName) ($($publishRequestBody | ConvertTo-Json -Compress))" + Invoke-RestMethod -Uri "$BaseUri/$($createRequestBody.requestName)" -Body ($publishRequestBody | ConvertTo-Json -Compress) -Verbose + displayName: Publish Symbols using internal REST API diff --git a/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml b/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml index f66d452b36a..37d21c89a69 100644 --- a/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml +++ b/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml @@ -52,6 +52,10 @@ parameters: - name: publishVpackToWindows type: boolean default: false + - name: symbolPublishingSubscription + type: string + - name: symbolPublishingProject + type: string - name: extraPublishJobs type: object @@ -248,12 +252,13 @@ extends: displayName: Publish dependsOn: [Build] jobs: - - template: ./build/pipelines/templates-v2/job-publish-symbols.yml@self + - template: ./build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml@self parameters: pool: { type: windows } includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }} - symbolPatGoesInTaskInputs: true # onebranch tries to muck with the PAT variable, so we need to change how it get the PAT symbolExpiryTime: ${{ parameters.symbolExpiryTime }} + subscription: ${{ parameters.symbolPublishingSubscription }} + symbolProject: ${{ parameters.symbolPublishingProject }} variables: ob_git_checkout: false # This job checks itself out ob_git_skip_checkout_none: true