mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-18 18:56:25 +00:00
Compare commits
62 Commits
v1.25.1241
...
dev/cazamo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3b7ff29fc | ||
|
|
9c2a507696 | ||
|
|
425a4036d4 | ||
|
|
408b232d13 | ||
|
|
9be7bf3130 | ||
|
|
efcc5f94f4 | ||
|
|
877c7c6555 | ||
|
|
59705d5905 | ||
|
|
4f86d4ceca | ||
|
|
b540827359 | ||
|
|
d37fb80d19 | ||
|
|
3dc426d685 | ||
|
|
a2e24f0221 | ||
|
|
d955d44e98 | ||
|
|
09bcdc0566 | ||
|
|
26644183f2 | ||
|
|
8f7a26d05c | ||
|
|
7a05a7c603 | ||
|
|
c370efbdad | ||
|
|
543c67771e | ||
|
|
5471c4c400 | ||
|
|
5d188ce593 | ||
|
|
82a986af94 | ||
|
|
62a6b5eb2f | ||
|
|
6cc6fe1714 | ||
|
|
14e380a9b2 | ||
|
|
9cbaa980d8 | ||
|
|
27d4a0b575 | ||
|
|
e14dfec7b7 | ||
|
|
672945c3bf | ||
|
|
d008e80d02 | ||
|
|
3252b7ddf0 | ||
|
|
fe4069dd13 | ||
|
|
3abee35102 | ||
|
|
acb19efea7 | ||
|
|
22ba243185 | ||
|
|
018fade640 | ||
|
|
6d968b54f3 | ||
|
|
20bdc21c79 | ||
|
|
a4c69cfc6a | ||
|
|
e5ea64586d | ||
|
|
81f881a579 | ||
|
|
45d75e701f | ||
|
|
83aa9fd889 | ||
|
|
8c99200e96 | ||
|
|
14bab6cc1a | ||
|
|
be2b1d30cb | ||
|
|
6fbf953fb2 | ||
|
|
cff62cc60e | ||
|
|
82536fd756 | ||
|
|
bf2e4e19d7 | ||
|
|
2706d05491 | ||
|
|
1dafcef36f | ||
|
|
53ddd92e7f | ||
|
|
e84e8d408f | ||
|
|
532343f1ce | ||
|
|
2a41f8a57c | ||
|
|
e56eb74788 | ||
|
|
cac844b1e9 | ||
|
|
915f085b60 | ||
|
|
1b8c99dff8 | ||
|
|
e01ff4faf0 |
2
.github/actions/spelling/allow/allow.txt
vendored
2
.github/actions/spelling/allow/allow.txt
vendored
@@ -71,7 +71,9 @@ sustainability
|
||||
sxn
|
||||
Tencent
|
||||
toolset
|
||||
Uids
|
||||
UEFI
|
||||
UIDs
|
||||
uiatextrange
|
||||
und
|
||||
vsdevcmd
|
||||
|
||||
4
.github/actions/spelling/expect/expect.txt
vendored
4
.github/actions/spelling/expect/expect.txt
vendored
@@ -256,7 +256,6 @@ conterm
|
||||
contsf
|
||||
contypes
|
||||
conwinuserrefs
|
||||
coordnew
|
||||
COPYCOLOR
|
||||
COPYDATA
|
||||
COPYDATASTRUCT
|
||||
@@ -622,7 +621,6 @@ fuzzmap
|
||||
fuzzwrapper
|
||||
fwdecl
|
||||
fwe
|
||||
fwlink
|
||||
fzf
|
||||
gci
|
||||
gcx
|
||||
@@ -866,6 +864,7 @@ KILLACTIVE
|
||||
KILLFOCUS
|
||||
kinda
|
||||
KIYEOK
|
||||
KKP
|
||||
KLF
|
||||
KLMNO
|
||||
KOK
|
||||
@@ -885,6 +884,7 @@ LBUTTONDOWN
|
||||
LBUTTONUP
|
||||
lcb
|
||||
lci
|
||||
LCMAP
|
||||
LCONTROL
|
||||
LCTRL
|
||||
lcx
|
||||
|
||||
@@ -600,90 +600,6 @@ namespace
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#pragma region TAEF hookup for the test case array above
|
||||
struct ArrayIndexTaefAdapterRow : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataRow>
|
||||
{
|
||||
HRESULT RuntimeClassInitialize(const size_t index)
|
||||
{
|
||||
_index = index;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestData(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
const auto indexString{ wil::str_printf<std::wstring>(L"%zu", _index) };
|
||||
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
|
||||
LONG index{ 0 };
|
||||
auto indexBstr{ wil::make_bstr(indexString.c_str()) };
|
||||
(void)SafeArrayPutElement(safeArray, &index, indexBstr.release());
|
||||
*ppData = safeArray;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadataNames(SAFEARRAY** ppMetadataNames) override
|
||||
{
|
||||
*ppMetadataNames = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadata(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
*ppData = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetName(BSTR* ppszRowName) override
|
||||
{
|
||||
*ppszRowName = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index;
|
||||
};
|
||||
|
||||
struct ArrayIndexTaefAdapterSource : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataSource>
|
||||
{
|
||||
STDMETHODIMP Advance(IDataRow** ppDataRow) override
|
||||
{
|
||||
if (_index < std::extent_v<decltype(testCases)>)
|
||||
{
|
||||
Microsoft::WRL::MakeAndInitialize<ArrayIndexTaefAdapterRow>(ppDataRow, _index++);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppDataRow = nullptr;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset() override
|
||||
{
|
||||
_index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataNames(SAFEARRAY** names) override
|
||||
{
|
||||
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
|
||||
LONG index{ 0 };
|
||||
auto dataNameBstr{ wil::make_bstr(L"index") };
|
||||
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.release());
|
||||
*names = safeArray;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataType(BSTR /*name*/, BSTR* type) override
|
||||
{
|
||||
*type = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index{ 0 };
|
||||
};
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
extern "C" HRESULT __declspec(dllexport) __cdecl ReflowTestDataSource(IDataSource** ppDataSource, void*)
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="FilteredCommand.h" />
|
||||
<ClInclude Include="Pane.h" />
|
||||
<ClInclude Include="fzf/fzf.h" />
|
||||
<ClInclude Include="../fzf/fzf.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="ShortcutActionDispatch.h">
|
||||
<DependentUpon>ShortcutActionDispatch.idl</DependentUpon>
|
||||
@@ -204,7 +204,7 @@
|
||||
<ClCompile Include="Tab.cpp">
|
||||
<DependentUpon>Tab.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="fzf/fzf.cpp" />
|
||||
<ClCompile Include="../fzf/fzf.cpp" />
|
||||
<ClCompile Include="TaskbarState.cpp">
|
||||
<DependentUpon>TaskbarState.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
|
||||
@@ -4916,7 +4916,7 @@ namespace winrt::TerminalApp::implementation
|
||||
theme.TabRow().UnfocusedBackground()) :
|
||||
ThemeColor{ nullptr } };
|
||||
|
||||
if (_settings.GlobalSettings().UseAcrylicInTabRow())
|
||||
if (_settings.GlobalSettings().UseAcrylicInTabRow() && (_activated || _settings.GlobalSettings().EnableUnfocusedAcrylic()))
|
||||
{
|
||||
if (tabRowBg)
|
||||
{
|
||||
|
||||
@@ -121,6 +121,7 @@ namespace Microsoft.Terminal.Core
|
||||
String WordDelimiters { get; };
|
||||
|
||||
Boolean ForceVTInput { get; };
|
||||
Boolean AllowKittyKeyboardMode { get; };
|
||||
Boolean AllowVtChecksumReport { get; };
|
||||
Boolean AllowVtClipboardWrite { get; };
|
||||
Boolean TrimBlockSelection { get; };
|
||||
|
||||
@@ -98,6 +98,7 @@ void Terminal::UpdateSettings(ICoreSettings settings)
|
||||
}
|
||||
|
||||
_getTerminalInput().ForceDisableWin32InputMode(settings.ForceVTInput());
|
||||
_getTerminalInput().ForceDisableKittyKeyboardProtocol(!settings.AllowKittyKeyboardMode());
|
||||
|
||||
if (settings.TabColor() == nullptr)
|
||||
{
|
||||
|
||||
@@ -349,6 +349,7 @@ namespace winrt::Microsoft::Terminal::Settings
|
||||
_ReloadEnvironmentVariables = profile.ReloadEnvironmentVariables();
|
||||
_RainbowSuggestions = profile.RainbowSuggestions();
|
||||
_ForceVTInput = profile.ForceVTInput();
|
||||
_AllowKittyKeyboardMode = profile.AllowKittyKeyboardMode();
|
||||
_AllowVtChecksumReport = profile.AllowVtChecksumReport();
|
||||
_AllowVtClipboardWrite = profile.AllowVtClipboardWrite();
|
||||
_PathTranslationStyle = profile.PathTranslationStyle();
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "pch.h"
|
||||
#include "Actions.h"
|
||||
#include "Actions.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "LibraryResources.h"
|
||||
#include "../TerminalSettingsModel/AllShortcutActions.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
@@ -20,16 +22,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Actions::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::ActionsViewModel>();
|
||||
_ViewModel.CurrentPage(ActionsSubPage::Base);
|
||||
auto vmImpl = get_self<ActionsViewModel>(_ViewModel);
|
||||
vmImpl->MarkAsVisited();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::ActionsViewModel>();
|
||||
get_self<ActionsViewModel>(_ViewModel)->MarkAsVisited();
|
||||
_layoutUpdatedRevoker = LayoutUpdated(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
// Only let this succeed once.
|
||||
_layoutUpdatedRevoker.revoke();
|
||||
|
||||
AddNewButton().Focus(FocusState::Programmatic);
|
||||
});
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -182,8 +182,7 @@
|
||||
</Page.Resources>
|
||||
|
||||
<Border MaxWidth="{StaticResource StandardControlMaxWidth}">
|
||||
<StackPanel MaxWidth="600"
|
||||
HorizontalAlignment="Left"
|
||||
<StackPanel HorizontalAlignment="Stretch"
|
||||
Spacing="8"
|
||||
Style="{StaticResource SettingsStackStyle}">
|
||||
<HyperlinkButton x:Uid="Actions_Disclaimer"
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void AddProfile::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_State = e.Parameter().as<Editor::AddProfilePageNavigationState>();
|
||||
BringIntoViewWhenLoaded(_State.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
struct AddProfilePageNavigationState : AddProfilePageNavigationStateT<AddProfilePageNavigationState>
|
||||
{
|
||||
public:
|
||||
AddProfilePageNavigationState(const Model::CascadiaSettings& settings) :
|
||||
_Settings{ settings } {}
|
||||
AddProfilePageNavigationState(const Model::CascadiaSettings& settings, const hstring& elementToFocus = {}) :
|
||||
_Settings{ settings },
|
||||
_ElementToFocus{ elementToFocus } {}
|
||||
|
||||
void RequestAddNew()
|
||||
{
|
||||
@@ -42,6 +43,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
til::event<AddNewArgs> AddNew;
|
||||
|
||||
WINRT_PROPERTY(Model::CascadiaSettings, Settings, nullptr);
|
||||
WINRT_PROPERTY(hstring, ElementToFocus);
|
||||
};
|
||||
|
||||
struct AddProfile : public HasScrollViewer<AddProfile>, AddProfileT<AddProfile>
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
runtimeclass AddProfilePageNavigationState
|
||||
{
|
||||
Microsoft.Terminal.Settings.Model.CascadiaSettings Settings;
|
||||
String ElementToFocus { get; };
|
||||
|
||||
void RequestAddNew();
|
||||
void RequestDuplicate(Guid profile);
|
||||
event AddNewArgs AddNew;
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
</Button>
|
||||
</Border>
|
||||
<StackPanel Margin="{StaticResource StandardControlMargin}">
|
||||
<local:SettingContainer x:Uid="AddProfile_Duplicate">
|
||||
<local:SettingContainer x:Name="DuplicateProfile"
|
||||
x:Uid="AddProfile_Duplicate">
|
||||
<ComboBox x:Name="Profiles"
|
||||
AutomationProperties.AccessibilityView="Content"
|
||||
ItemsSource="{x:Bind State.Settings.AllProfiles, Mode=OneWay}"
|
||||
|
||||
@@ -1138,6 +1138,27 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
INITIALIZE_BINDABLE_ENUM_SETTING(IntenseTextStyle, IntenseTextStyle, winrt::Microsoft::Terminal::Settings::Model::IntenseStyle, L"Appearance_IntenseTextStyle", L"Content");
|
||||
}
|
||||
|
||||
// Appearances doesn't implement HasScrollViewer<T> which normally adds this function.
|
||||
void Appearances::BringIntoViewWhenLoaded(hstring elementToFocus)
|
||||
{
|
||||
if (elementToFocus.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_loadedRevoker = this->Loaded(winrt::auto_revoke, [weakThis{ get_weak() }, elementToFocus](auto&&, auto&&) {
|
||||
if (const auto strongThis = weakThis.get())
|
||||
{
|
||||
if (const auto& controlToFocus{ strongThis->FindName(elementToFocus).try_as<Controls::Control>() })
|
||||
{
|
||||
controlToFocus.as<FrameworkElement>().StartBringIntoView();
|
||||
controlToFocus.Focus(FocusState::Programmatic);
|
||||
}
|
||||
strongThis->_loadedRevoker.revoke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
IObservableVector<Editor::Font> Appearances::FilteredFontList()
|
||||
{
|
||||
if (!_filteredFonts)
|
||||
|
||||
@@ -188,6 +188,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
struct Appearances : AppearancesT<Appearances>
|
||||
{
|
||||
Appearances();
|
||||
void BringIntoViewWhenLoaded(hstring elementToFocus);
|
||||
|
||||
// CursorShape visibility logic
|
||||
bool IsVintageCursor() const;
|
||||
@@ -213,6 +214,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
bool IsCustomFontWeight();
|
||||
|
||||
til::property_changed_event PropertyChanged;
|
||||
winrt::Windows::UI::Xaml::FrameworkElement::Loaded_revoker _loadedRevoker;
|
||||
|
||||
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Microsoft::Terminal::Settings::Editor::EnumEntry>, FontWeightList);
|
||||
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
<!-- Color Scheme -->
|
||||
<!-- This currently only display the Dark color scheme, even if the user has a pair of schemes set. -->
|
||||
<local:SettingContainer x:Uid="Profile_ColorScheme"
|
||||
<local:SettingContainer x:Name="ColorScheme"
|
||||
x:Uid="Profile_ColorScheme"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearColorScheme}"
|
||||
CurrentValueAccessibleName="{x:Bind Appearance.CurrentColorScheme.Name, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Appearance.HasDarkColorSchemeName, Mode=OneWay}"
|
||||
@@ -284,17 +285,20 @@
|
||||
IsChecked="{x:Bind ShowAllFonts, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
<local:SettingContainer x:Uid="Profile_MissingFontFaces"
|
||||
<local:SettingContainer x:Name="MissingFontFaces"
|
||||
x:Uid="Profile_MissingFontFaces"
|
||||
HelpText="{x:Bind Appearance.MissingFontFaces, Mode=OneWay}"
|
||||
Style="{StaticResource SettingContainerErrorStyle}"
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Appearance.MissingFontFaces), Mode=OneWay}" />
|
||||
<local:SettingContainer x:Uid="Profile_ProportionalFontFaces"
|
||||
<local:SettingContainer x:Name="ProportionalFontFaces"
|
||||
x:Uid="Profile_ProportionalFontFaces"
|
||||
HelpText="{x:Bind Appearance.ProportionalFontFaces, Mode=OneWay}"
|
||||
Style="{StaticResource SettingContainerWarningStyle}"
|
||||
Visibility="{x:Bind mtu:Converters.StringNotEmptyToVisibility(Appearance.ProportionalFontFaces), Mode=OneWay}" />
|
||||
|
||||
<!-- Font Size -->
|
||||
<local:SettingContainer x:Uid="Profile_FontSize"
|
||||
<local:SettingContainer x:Name="FontSize"
|
||||
x:Uid="Profile_FontSize"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontSize}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontSize, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontSizeOverrideSource, Mode=OneWay}"
|
||||
@@ -310,7 +314,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Line Height -->
|
||||
<local:SettingContainer x:Uid="Profile_LineHeight"
|
||||
<local:SettingContainer x:Name="LineHeight"
|
||||
x:Uid="Profile_LineHeight"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearLineHeight}"
|
||||
HasSettingValue="{x:Bind Appearance.HasLineHeight, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.LineHeightOverrideSource, Mode=OneWay}"
|
||||
@@ -326,7 +331,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Cell Width -->
|
||||
<local:SettingContainer x:Uid="Profile_CellWidth"
|
||||
<local:SettingContainer x:Name="CellWidth"
|
||||
x:Uid="Profile_CellWidth"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearCellWidth}"
|
||||
HasSettingValue="{x:Bind Appearance.HasCellWidth, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.CellWidthOverrideSource, Mode=OneWay}"
|
||||
@@ -342,7 +348,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Font Weight -->
|
||||
<local:SettingContainer x:Uid="Profile_FontWeight"
|
||||
<local:SettingContainer x:Name="FontWeight"
|
||||
x:Uid="Profile_FontWeight"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontWeight}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontWeight, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontWeightOverrideSource, Mode=OneWay}"
|
||||
@@ -378,7 +385,8 @@
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
<local:SettingContainer x:Uid="Profile_FontAxes"
|
||||
<local:SettingContainer x:Name="FontAxes"
|
||||
x:Uid="Profile_FontAxes"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontAxes}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontAxes, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontAxesOverrideSource, Mode=OneWay}"
|
||||
@@ -405,7 +413,8 @@
|
||||
</muxc:DropDownButton>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
<local:SettingContainer x:Uid="Profile_FontFeatures"
|
||||
<local:SettingContainer x:Name="FontFeatures"
|
||||
x:Uid="Profile_FontFeatures"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearFontFeatures}"
|
||||
HasSettingValue="{x:Bind Appearance.HasFontFeatures, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.FontFeaturesOverrideSource, Mode=OneWay}"
|
||||
@@ -434,7 +443,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Builtin Glyphs -->
|
||||
<local:SettingContainer x:Uid="Profile_EnableBuiltinGlyphs"
|
||||
<local:SettingContainer x:Name="EnableBuiltinGlyphs"
|
||||
x:Uid="Profile_EnableBuiltinGlyphs"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearEnableBuiltinGlyphs}"
|
||||
HasSettingValue="{x:Bind Appearance.HasEnableBuiltinGlyphs, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.EnableBuiltinGlyphsOverrideSource, Mode=OneWay}">
|
||||
@@ -443,7 +453,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Color Glyphs -->
|
||||
<local:SettingContainer x:Uid="Profile_EnableColorGlyphs"
|
||||
<local:SettingContainer x:Name="EnableColorGlyphs"
|
||||
x:Uid="Profile_EnableColorGlyphs"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearEnableColorGlyphs}"
|
||||
HasSettingValue="{x:Bind Appearance.HasEnableColorGlyphs, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.EnableColorGlyphsOverrideSource, Mode=OneWay}">
|
||||
@@ -452,7 +463,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Retro Terminal Effect -->
|
||||
<local:SettingContainer x:Uid="Profile_RetroTerminalEffect"
|
||||
<local:SettingContainer x:Name="RetroTerminalEffect"
|
||||
x:Uid="Profile_RetroTerminalEffect"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearRetroTerminalEffect}"
|
||||
HasSettingValue="{x:Bind Appearance.HasRetroTerminalEffect, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.RetroTerminalEffectOverrideSource, Mode=OneWay}">
|
||||
@@ -461,7 +473,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Adjust Indistinguishable Colors -->
|
||||
<local:SettingContainer x:Uid="Profile_AdjustIndistinguishableColors"
|
||||
<local:SettingContainer x:Name="AdjustIndistinguishableColors"
|
||||
x:Uid="Profile_AdjustIndistinguishableColors"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearAdjustIndistinguishableColors}"
|
||||
HasSettingValue="{x:Bind Appearance.HasAdjustIndistinguishableColors, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.AdjustIndistinguishableColorsOverrideSource, Mode=OneWay}">
|
||||
@@ -479,7 +492,8 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Cursor Shape -->
|
||||
<local:SettingContainer x:Uid="Profile_CursorShape"
|
||||
<local:SettingContainer x:Name="CursorShape"
|
||||
x:Uid="Profile_CursorShape"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearCursorShape}"
|
||||
HasSettingValue="{x:Bind Appearance.HasCursorShape, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.CursorShapeOverrideSource, Mode=OneWay}">
|
||||
@@ -491,7 +505,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Cursor Height -->
|
||||
<local:SettingContainer x:Uid="Profile_CursorHeight"
|
||||
<local:SettingContainer x:Name="CursorHeight"
|
||||
x:Uid="Profile_CursorHeight"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearCursorHeight}"
|
||||
HasSettingValue="{x:Bind Appearance.HasCursorHeight, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.CursorHeightOverrideSource, Mode=OneWay}"
|
||||
@@ -563,7 +578,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Background Image Stretch Mode -->
|
||||
<local:SettingContainer x:Uid="Profile_BackgroundImageStretchMode"
|
||||
<local:SettingContainer x:Name="BackgroundImageStretchMode"
|
||||
x:Uid="Profile_BackgroundImageStretchMode"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageStretchMode}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageStretchMode, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImageStretchModeOverrideSource, Mode=OneWay}"
|
||||
@@ -576,7 +592,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Background Image Alignment -->
|
||||
<local:SettingContainer x:Uid="Profile_BackgroundImageAlignment"
|
||||
<local:SettingContainer x:Name="BackgroundImageAlignment"
|
||||
x:Uid="Profile_BackgroundImageAlignment"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageAlignment}"
|
||||
CurrentValue="{x:Bind Appearance.BackgroundImageAlignmentCurrentValue, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageAlignment, Mode=OneWay}"
|
||||
@@ -764,7 +781,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Background Image Opacity -->
|
||||
<local:SettingContainer x:Uid="Profile_BackgroundImageOpacity"
|
||||
<local:SettingContainer x:Name="BackgroundImageOpacity"
|
||||
x:Uid="Profile_BackgroundImageOpacity"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearBackgroundImageOpacity}"
|
||||
HasSettingValue="{x:Bind Appearance.HasBackgroundImageOpacity, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.BackgroundImageOpacityOverrideSource, Mode=OneWay}"
|
||||
@@ -790,7 +808,8 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Intense is bold, bright -->
|
||||
<local:SettingContainer x:Uid="Appearance_IntenseTextStyle"
|
||||
<local:SettingContainer x:Name="IntenseTextStyle"
|
||||
x:Uid="Appearance_IntenseTextStyle"
|
||||
ClearSettingValue="{x:Bind Appearance.ClearIntenseTextStyle}"
|
||||
HasSettingValue="{x:Bind Appearance.HasIntenseTextStyle, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Appearance.IntenseTextStyleOverrideSource, Mode=OneWay}">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "ColorSchemes.h"
|
||||
#include "ColorTableEntry.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "ColorSchemes.g.cpp"
|
||||
|
||||
using namespace winrt;
|
||||
@@ -33,9 +34,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void ColorSchemes::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::ColorSchemesPageViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::ColorSchemesPageViewModel>();
|
||||
_ViewModel.CurrentPage(ColorSchemesSubPage::Base);
|
||||
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
_layoutUpdatedRevoker = LayoutUpdated(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
// Only let this succeed once.
|
||||
_layoutUpdatedRevoker.revoke();
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(ColorSchemesSubPage, CurrentPage, _propertyChangedHandlers, ColorSchemesSubPage::Base);
|
||||
WINRT_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel>, AllColorSchemes, _propertyChangedHandlers, nullptr);
|
||||
WINRT_PROPERTY(hstring, ElementToFocus);
|
||||
|
||||
private:
|
||||
Editor::ColorSchemeViewModel _CurrentScheme{ nullptr };
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "EnumEntry.h"
|
||||
#include "Compatibility.g.cpp"
|
||||
#include "CompatibilityViewModel.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
@@ -54,7 +55,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Compatibility::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::CompatibilityViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::CompatibilityViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -26,13 +26,15 @@
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Allow Headless -->
|
||||
<local:SettingContainer x:Uid="Globals_AllowHeadless">
|
||||
<local:SettingContainer x:Name="AllowHeadless"
|
||||
x:Uid="Globals_AllowHeadless">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AllowHeadless, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Text Measurement -->
|
||||
<local:SettingContainer x:Uid="Globals_TextMeasurement">
|
||||
<local:SettingContainer x:Name="TextMeasurement"
|
||||
x:Uid="Globals_TextMeasurement">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.TextMeasurementList}"
|
||||
@@ -41,14 +43,16 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Debug Features -->
|
||||
<local:SettingContainer x:Uid="Globals_DebugFeaturesEnabled"
|
||||
<local:SettingContainer x:Name="DebugFeaturesEnabled"
|
||||
x:Uid="Globals_DebugFeaturesEnabled"
|
||||
Visibility="{x:Bind ViewModel.DebugFeaturesAvailable}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.DebugFeaturesEnabled, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Reset Application State -->
|
||||
<local:SettingContainer x:Uid="Settings_ResetApplicationState">
|
||||
<local:SettingContainer x:Name="ResetApplicationState"
|
||||
x:Uid="Settings_ResetApplicationState">
|
||||
<Button x:Uid="Settings_ResetApplicationStateButton"
|
||||
Style="{StaticResource DeleteButtonStyle}">
|
||||
<Button.Flyout>
|
||||
@@ -69,7 +73,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Reset to Default Settings -->
|
||||
<local:SettingContainer x:Uid="Settings_ResetToDefaultSettings">
|
||||
<local:SettingContainer x:Name="ResetToDefaultSettings"
|
||||
x:Uid="Settings_ResetToDefaultSettings">
|
||||
<Button x:Uid="Settings_ResetToDefaultSettingsButton"
|
||||
Style="{StaticResource DeleteButtonStyle}">
|
||||
<Button.Flyout>
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include "../TerminalSettingsModel/AllShortcutActions.h"
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
@@ -49,5 +51,82 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
CommandNameTextBox().Focus(FocusState::Programmatic);
|
||||
});
|
||||
|
||||
// Initialize AutoSuggestBox with current action and store last valid action
|
||||
if (_ViewModel.ProposedShortcutActionName())
|
||||
{
|
||||
const auto currentAction = winrt::unbox_value<winrt::hstring>(_ViewModel.ProposedShortcutActionName());
|
||||
ShortcutActionBox().Text(currentAction);
|
||||
_lastValidAction = currentAction;
|
||||
}
|
||||
}
|
||||
|
||||
void EditAction::ShortcutActionBox_GotFocus(const IInspectable& sender, const RoutedEventArgs&)
|
||||
{
|
||||
// Open the suggestions list with all available actions
|
||||
std::vector<winrt::hstring> allActions;
|
||||
for (const auto& action : _ViewModel.AvailableShortcutActions())
|
||||
{
|
||||
allActions.push_back(action);
|
||||
}
|
||||
|
||||
_filteredActions = winrt::single_threaded_observable_vector(std::move(allActions));
|
||||
sender.as<AutoSuggestBox>().ItemsSource(_filteredActions);
|
||||
sender.as<AutoSuggestBox>().IsSuggestionListOpen(true);
|
||||
}
|
||||
|
||||
void EditAction::ShortcutActionBox_TextChanged(const AutoSuggestBox& sender, const AutoSuggestBoxTextChangedEventArgs& args)
|
||||
{
|
||||
if (args.Reason() == AutoSuggestionBoxTextChangeReason::UserInput)
|
||||
{
|
||||
const auto searchText = sender.Text();
|
||||
std::vector<winrt::hstring> filtered;
|
||||
|
||||
for (const auto& action : _ViewModel.AvailableShortcutActions())
|
||||
{
|
||||
if (til::contains_linguistic_insensitive(action, searchText))
|
||||
{
|
||||
filtered.push_back(action);
|
||||
}
|
||||
}
|
||||
|
||||
_filteredActions = winrt::single_threaded_observable_vector(std::move(filtered));
|
||||
sender.ItemsSource(_filteredActions);
|
||||
}
|
||||
}
|
||||
|
||||
void EditAction::ShortcutActionBox_SuggestionChosen(const AutoSuggestBox& sender, const AutoSuggestBoxSuggestionChosenEventArgs& args)
|
||||
{
|
||||
if (const auto selectedAction = args.SelectedItem().try_as<winrt::hstring>())
|
||||
{
|
||||
sender.Text(*selectedAction);
|
||||
}
|
||||
}
|
||||
|
||||
void EditAction::ShortcutActionBox_QuerySubmitted(const AutoSuggestBox& sender, const AutoSuggestBoxQuerySubmittedEventArgs& args)
|
||||
{
|
||||
const auto submittedText = args.QueryText();
|
||||
|
||||
// Validate that this is a valid shortcut action
|
||||
bool isValid = false;
|
||||
for (const auto& action : _ViewModel.AvailableShortcutActions())
|
||||
{
|
||||
if (action == submittedText)
|
||||
{
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
_ViewModel.ProposedShortcutActionName(winrt::box_value(submittedText));
|
||||
_lastValidAction = submittedText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Revert to the last valid action
|
||||
sender.Text(_lastValidAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
WINRT_OBSERVABLE_PROPERTY(Editor::CommandViewModel, ViewModel, PropertyChanged.raise, nullptr);
|
||||
|
||||
void ShortcutActionBox_GotFocus(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void ShortcutActionBox_TextChanged(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const winrt::Windows::UI::Xaml::Controls::AutoSuggestBoxTextChangedEventArgs& args);
|
||||
void ShortcutActionBox_SuggestionChosen(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const winrt::Windows::UI::Xaml::Controls::AutoSuggestBoxSuggestionChosenEventArgs& args);
|
||||
void ShortcutActionBox_QuerySubmitted(const winrt::Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const winrt::Windows::UI::Xaml::Controls::AutoSuggestBoxQuerySubmittedEventArgs& args);
|
||||
|
||||
private:
|
||||
friend struct EditActionT<EditAction>; // for Xaml to bind events
|
||||
winrt::Windows::UI::Xaml::FrameworkElement::LayoutUpdated_revoker _layoutUpdatedRevoker;
|
||||
Editor::CommandViewModel::PropagateWindowRootRequested_revoker _propagateWindowRootRevoker;
|
||||
Editor::CommandViewModel::FocusContainer_revoker _focusContainerRevoker;
|
||||
winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> _filteredActions{ nullptr };
|
||||
winrt::hstring _lastValidAction;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -157,24 +157,30 @@
|
||||
<Setter Property="Height" Value="{StaticResource EditButtonSize}" />
|
||||
<Setter Property="Width" Value="{StaticResource EditButtonSize}" />
|
||||
</Style>
|
||||
<Style x:Key="TextBlockGroupingStyle"
|
||||
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="MaxWidth" Value="{StaticResource StandardControlMaxWidth}" />
|
||||
<Setter Property="Margin" Value="0,0,0,4" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
</Style>
|
||||
|
||||
<!-- Templates -->
|
||||
<DataTemplate x:Key="KeyChordTemplate"
|
||||
x:DataType="local:KeyChordViewModel">
|
||||
<ListViewItem IsTabStop="False"
|
||||
Style="{StaticResource KeyBindingContainerStyle}">
|
||||
<Grid Padding="2,0,2,0"
|
||||
<Grid Padding="-4,0,0,0"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
Background="{ThemeResource AppBarItemBackgroundThemeBrush}"
|
||||
Click="{x:Bind ToggleEditMode}"
|
||||
Style="{ThemeResource KeyChordBorderStyle}"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}">
|
||||
<TextBlock FontSize="14"
|
||||
Style="{ThemeResource KeyChordTextBlockStyle}"
|
||||
Text="{x:Bind KeyChordText, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Button>
|
||||
@@ -214,6 +220,7 @@
|
||||
</Grid>
|
||||
<Button Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
AutomationProperties.Name="{x:Bind DeleteButtonName}"
|
||||
Style="{StaticResource DeleteSmallButtonStyle}">
|
||||
<Button.Content>
|
||||
@@ -243,13 +250,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<muxc:NumberBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
LargeChange="1"
|
||||
Maximum="100"
|
||||
@@ -267,13 +275,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<muxc:NumberBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
LargeChange="1"
|
||||
Maximum="999"
|
||||
@@ -291,13 +300,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<muxc:NumberBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
LargeChange="1"
|
||||
Maximum="999"
|
||||
@@ -315,13 +325,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<muxc:NumberBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
LargeChange="1"
|
||||
Maximum="999"
|
||||
@@ -339,13 +350,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<muxc:NumberBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
LargeChange="1"
|
||||
Maximum="999"
|
||||
@@ -363,13 +375,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<muxc:NumberBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
LargeChange="0.2"
|
||||
Maximum="1"
|
||||
@@ -387,7 +400,7 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto"
|
||||
<ColumnDefinition Width="*"
|
||||
MinWidth="196" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
@@ -408,13 +421,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<ComboBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind EnumList, Mode=OneWay}"
|
||||
@@ -482,13 +496,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<ToggleSwitch Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
IsOn="{x:Bind UnboxBool(Value), Mode=TwoWay, BindBack=BoolOptionalBindBack}" />
|
||||
</Grid>
|
||||
@@ -501,13 +516,15 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<CheckBox Grid.Column="1"
|
||||
Margin="0,0,-96,0"
|
||||
HorizontalAlignment="Right"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
IsChecked="{x:Bind UnboxBoolOptional(Value), Mode=TwoWay, BindBack=BoolOptionalBindBack}"
|
||||
IsThreeState="True" />
|
||||
@@ -526,13 +543,14 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind Name}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<ComboBox Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind EnumList, Mode=OneWay}"
|
||||
@@ -572,7 +590,7 @@
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<ItemsControl Grid.Column="1"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalAlignment="Right"
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
ItemTemplate="{StaticResource FlagItemTemplate}"
|
||||
ItemsSource="{x:Bind FlagList, Mode=OneWay}" />
|
||||
@@ -586,7 +604,7 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
@@ -608,7 +626,7 @@
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{StaticResource ArgumentNameWidth}" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
@@ -646,73 +664,88 @@
|
||||
|
||||
<Border MaxWidth="{StaticResource StandardControlMaxWidth}"
|
||||
Margin="{StaticResource SettingStackMargin}">
|
||||
<Grid MaxWidth="600"
|
||||
Margin="{StaticResource SettingStackMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
<Grid Margin="{StaticResource SettingStackMargin}"
|
||||
HorizontalAlignment="Stretch"
|
||||
ColumnSpacing="16"
|
||||
RowSpacing="8">
|
||||
RowSpacing="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Uid="Actions_Name"
|
||||
<TextBlock x:Uid="Actions_CommandDetails"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource TextBlockGroupingStyle}" />
|
||||
<TextBlock x:Uid="Actions_Name"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox x:Name="CommandNameTextBox"
|
||||
Grid.Row="0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.ActionNameTextBoxAutomationPropName}"
|
||||
PlaceholderText="{x:Bind ViewModel.DisplayName, Mode=OneWay}"
|
||||
Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />
|
||||
<TextBlock x:Uid="Actions_ShortcutAction"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center" />
|
||||
<ComboBox Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.ShortcutActionComboBoxAutomationPropName}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableShortcutActions, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.ProposedShortcutActionName, Mode=TwoWay}" />
|
||||
<TextBlock x:Uid="Actions_Arguments"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{x:Bind ViewModel.ActionArgsVM.HasArgs, Mode=OneWay}" />
|
||||
<ItemsControl Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.AdditionalArgumentsControlAutomationPropName}"
|
||||
IsTabStop="False"
|
||||
ItemTemplateSelector="{StaticResource ArgsTemplateSelector}"
|
||||
ItemsSource="{x:Bind ViewModel.ActionArgsVM.ArgValues, Mode=OneWay}" />
|
||||
VerticalAlignment="Center" />
|
||||
<AutoSuggestBox x:Name="ShortcutActionBox"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.ShortcutActionComboBoxAutomationPropName}"
|
||||
GotFocus="ShortcutActionBox_GotFocus"
|
||||
QuerySubmitted="ShortcutActionBox_QuerySubmitted"
|
||||
SuggestionChosen="ShortcutActionBox_SuggestionChosen"
|
||||
TextChanged="ShortcutActionBox_TextChanged" />
|
||||
<TextBlock x:Uid="Actions_Keybindings"
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center" />
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource TextBlockGroupingStyle}" />
|
||||
<ListView x:Name="KeyChordListView"
|
||||
x:Uid="Actions_KeyBindingsListView"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
ItemTemplate="{StaticResource KeyChordTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.KeyChordList, Mode=OneWay}"
|
||||
SelectionMode="None">
|
||||
<ListView.Header>
|
||||
<Button Click="{x:Bind ViewModel.AddKeybinding_Click}">
|
||||
<Button Margin="0,0,0,4"
|
||||
Click="{x:Bind ViewModel.AddKeybinding_Click}">
|
||||
<TextBlock x:Uid="Actions_AddKeyChord" />
|
||||
</Button>
|
||||
</ListView.Header>
|
||||
</ListView>
|
||||
<Button Grid.Row="4"
|
||||
<TextBlock x:Uid="Actions_Arguments"
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource TextBlockGroupingStyle}"
|
||||
Visibility="{x:Bind ViewModel.ActionArgsVM.HasArgs, Mode=OneWay}" />
|
||||
<ItemsControl Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="{x:Bind ViewModel.AdditionalArgumentsControlAutomationPropName}"
|
||||
IsTabStop="False"
|
||||
ItemTemplateSelector="{StaticResource ArgsTemplateSelector}"
|
||||
ItemsSource="{x:Bind ViewModel.ActionArgsVM.ArgValues, Mode=OneWay}" />
|
||||
<Button Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
IsEnabled="{x:Bind ViewModel.IsUserAction, Mode=OneWay}"
|
||||
Style="{StaticResource DeleteButtonStyle}">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "EditColorScheme.h"
|
||||
#include "EditColorScheme.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace winrt::Windows::UI;
|
||||
@@ -38,7 +39,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void EditColorScheme::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::ColorSchemeViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::ColorSchemeViewModel>();
|
||||
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
const auto schemeName = _ViewModel.Name();
|
||||
NameBox().Text(schemeName);
|
||||
|
||||
@@ -200,7 +200,8 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<local:SettingContainer x:Uid="ColorScheme_InboxSchemeDuplicate"
|
||||
<local:SettingContainer x:Name="InboxSchemeDuplicate"
|
||||
x:Uid="ColorScheme_InboxSchemeDuplicate"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(ViewModel.IsEditable), Mode=OneWay}">
|
||||
<Button x:Name="DuplicateSchemeButton"
|
||||
x:Uid="ColorScheme_DuplicateButton"
|
||||
@@ -208,7 +209,8 @@
|
||||
Style="{StaticResource BrowseButtonStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<local:SettingContainer x:Uid="ColorScheme_ColorsHeader"
|
||||
<local:SettingContainer x:Name="ColorsHeader"
|
||||
x:Uid="ColorScheme_ColorsHeader"
|
||||
StartExpanded="True"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}"
|
||||
Visibility="{x:Bind ViewModel.IsEditable, Mode=OneWay}">
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "Extensions.h"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "Extensions.g.cpp"
|
||||
#include "ExtensionPackageViewModel.g.cpp"
|
||||
#include "ExtensionsViewModel.g.cpp"
|
||||
#include "FragmentProfileViewModel.g.cpp"
|
||||
#include "ExtensionPackageTemplateSelector.g.cpp"
|
||||
#include "NavConstants.h"
|
||||
|
||||
#include "..\WinRTUtils\inc\Utils.h"
|
||||
|
||||
@@ -33,11 +35,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Extensions::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::ExtensionsViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::ExtensionsViewModel>();
|
||||
|
||||
auto vmImpl = get_self<ExtensionsViewModel>(_ViewModel);
|
||||
vmImpl->ExtensionPackageIdentifierTemplateSelector(_extensionPackageIdentifierTemplateSelector);
|
||||
vmImpl->LazyLoadExtensions();
|
||||
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
if (vmImpl->IsExtensionView())
|
||||
{
|
||||
const auto currentPkgVM = vmImpl->CurrentExtensionPackage();
|
||||
@@ -452,6 +458,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
hstring ExtensionPackageViewModel::DisplayName() const noexcept
|
||||
{
|
||||
// Fragment extensions may not have a DisplayName, so fall back to Source
|
||||
const auto displayName = _package.DisplayName();
|
||||
return displayName.empty() ? _package.Source() : displayName;
|
||||
}
|
||||
|
||||
hstring ExtensionPackageViewModel::Icon() const noexcept
|
||||
{
|
||||
// Fragment extensions may not have an Icon, so fall back to the extensions nav icon glyph
|
||||
const auto icon = _package.Icon();
|
||||
return icon.empty() ? NavTagIconMap[extensionsTag] : icon;
|
||||
}
|
||||
|
||||
hstring ExtensionPackageViewModel::Scope() const noexcept
|
||||
{
|
||||
return _package.Scope() == Model::FragmentScope::User ? RS_(L"Extensions_ScopeUser") : RS_(L"Extensions_ScopeSystem");
|
||||
|
||||
@@ -93,6 +93,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void UpdateSettings(const Model::CascadiaSettings& settings);
|
||||
|
||||
Model::ExtensionPackage Package() const noexcept { return _package; }
|
||||
hstring DisplayName() const noexcept;
|
||||
hstring Icon() const noexcept;
|
||||
hstring Scope() const noexcept;
|
||||
bool Enabled() const;
|
||||
void Enabled(bool val);
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
[default_interface] runtimeclass ExtensionPackageViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
{
|
||||
Microsoft.Terminal.Settings.Model.ExtensionPackage Package { get; };
|
||||
String DisplayName { get; };
|
||||
String Icon { get; };
|
||||
Boolean Enabled;
|
||||
String Scope { get; };
|
||||
String AccessibleName { get; };
|
||||
|
||||
@@ -500,7 +500,8 @@
|
||||
<muxc:Expander.Content>
|
||||
<StackPanel>
|
||||
<!-- Scope -->
|
||||
<local:SettingContainer x:Uid="Extensions_Scope"
|
||||
<local:SettingContainer x:Name="Scope"
|
||||
x:Uid="Extensions_Scope"
|
||||
Content="{x:Bind ViewModel.CurrentExtensionPackage.Scope, Mode=OneWay}"
|
||||
IsTabStop="False"
|
||||
Style="{StaticResource SettingContainerWithTextContent}" />
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "GlobalAppearance.h"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "GlobalAppearance.g.cpp"
|
||||
|
||||
#include <WtExeUtils.h>
|
||||
@@ -23,7 +24,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void GlobalAppearance::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::GlobalAppearanceViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::GlobalAppearanceViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -5,7 +5,7 @@ import "GlobalAppearanceViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
[default_interface] runtimeclass GlobalAppearance : Windows.UI.Xaml.Controls.Page
|
||||
runtimeclass GlobalAppearance : Windows.UI.Xaml.Controls.Page
|
||||
{
|
||||
GlobalAppearance();
|
||||
GlobalAppearanceViewModel ViewModel { get; };
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Theme -->
|
||||
<local:SettingContainer x:Uid="Globals_Theme">
|
||||
<local:SettingContainer x:Name="Theme"
|
||||
x:Uid="Globals_Theme">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemsSource="{x:Bind ViewModel.ThemeList, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.CurrentTheme, Mode=TwoWay}"
|
||||
@@ -42,7 +43,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Position of new tab -->
|
||||
<local:SettingContainer x:Uid="Globals_NewTabPosition">
|
||||
<local:SettingContainer x:Name="NewTabPosition"
|
||||
x:Uid="Globals_NewTabPosition">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.NewTabPositionList, Mode=OneWay}"
|
||||
@@ -51,45 +53,52 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show Titlebar -->
|
||||
<local:SettingContainer x:Uid="Globals_ShowTitlebar">
|
||||
<local:SettingContainer x:Name="ShowTitlebar"
|
||||
x:Uid="Globals_ShowTitlebar">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsInTitlebar, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}"
|
||||
Toggled="{x:Bind ViewModel.ShowTitlebarToggled}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Always show tabs -->
|
||||
<local:SettingContainer x:Uid="Globals_AlwaysShowTabs">
|
||||
<local:SettingContainer x:Name="AlwaysShowTabs"
|
||||
x:Uid="Globals_AlwaysShowTabs">
|
||||
<ToggleSwitch IsEnabled="{x:Bind mtu:Converters.InvertBoolean(ViewModel.ShowTabsInTitlebar), Mode=OneWay}"
|
||||
IsOn="{x:Bind ViewModel.AlwaysShowTabs, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show tabs in full screen -->
|
||||
<local:SettingContainer x:Uid="Globals_ShowTabsFullscreen">
|
||||
<local:SettingContainer x:Name="ShowTabsFullscreen"
|
||||
x:Uid="Globals_ShowTabsFullscreen">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTabsFullscreen, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show Acrylic in Tab Row -->
|
||||
<local:SettingContainer x:Uid="Globals_AcrylicTabRow">
|
||||
<local:SettingContainer x:Name="AcrylicTabRow"
|
||||
x:Uid="Globals_AcrylicTabRow">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.UseAcrylicInTabRow, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show Title in Titlebar -->
|
||||
<local:SettingContainer x:Uid="Globals_ShowTitleInTitlebar">
|
||||
<local:SettingContainer x:Name="ShowTitleInTitlebar"
|
||||
x:Uid="Globals_ShowTitleInTitlebar">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowTitleInTitlebar, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Always on Top -->
|
||||
<local:SettingContainer x:Uid="Globals_AlwaysOnTop">
|
||||
<local:SettingContainer x:Name="AlwaysOnTop"
|
||||
x:Uid="Globals_AlwaysOnTop">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysOnTop, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Tab Width Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_TabWidthMode">
|
||||
<local:SettingContainer x:Name="TabWidthMode"
|
||||
x:Uid="Globals_TabWidthMode">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.TabWidthModeList, Mode=OneWay}"
|
||||
@@ -99,37 +108,43 @@
|
||||
|
||||
<!-- Disable Animations -->
|
||||
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
|
||||
<local:SettingContainer x:Uid="Globals_DisableAnimationsReversed">
|
||||
<local:SettingContainer x:Name="DisableAnimations"
|
||||
x:Uid="Globals_DisableAnimationsReversed">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.InvertedDisableAnimations, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Always Show Notification Icon -->
|
||||
<local:SettingContainer x:Uid="Globals_AlwaysShowNotificationIcon">
|
||||
<local:SettingContainer x:Name="AlwaysShowNotificationIcon"
|
||||
x:Uid="Globals_AlwaysShowNotificationIcon">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AlwaysShowNotificationIcon, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Minimize To Notification Area -->
|
||||
<local:SettingContainer x:Uid="Globals_MinimizeToNotificationArea">
|
||||
<local:SettingContainer x:Name="MinimizeToNotificationArea"
|
||||
x:Uid="Globals_MinimizeToNotificationArea">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.MinimizeToNotificationArea, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Automatically hide window -->
|
||||
<local:SettingContainer x:Uid="Globals_AutoHideWindow">
|
||||
<local:SettingContainer x:Name="AutoHideWindow"
|
||||
x:Uid="Globals_AutoHideWindow">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.AutoHideWindow, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Show Admin Shield -->
|
||||
<local:SettingContainer x:Uid="Globals_ShowAdminShield">
|
||||
<local:SettingContainer x:Name="ShowAdminShield"
|
||||
x:Uid="Globals_ShowAdminShield">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowAdminShield, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Enable Unfocused Acrylic -->
|
||||
<local:SettingContainer x:Uid="Globals_EnableUnfocusedAcrylic">
|
||||
<local:SettingContainer x:Name="EnableUnfocusedAcrylic"
|
||||
x:Uid="Globals_EnableUnfocusedAcrylic">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.EnableUnfocusedAcrylic, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "Interaction.h"
|
||||
#include "Interaction.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
|
||||
#include "EnumEntry.h"
|
||||
|
||||
@@ -21,7 +22,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Interaction::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::InteractionViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::InteractionViewModel>();
|
||||
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -27,13 +27,15 @@
|
||||
<StackPanel>
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Copy On Select -->
|
||||
<local:SettingContainer x:Uid="Globals_CopyOnSelect">
|
||||
<local:SettingContainer x:Name="CopyOnSelect"
|
||||
x:Uid="Globals_CopyOnSelect">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.CopyOnSelect, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Copy Format -->
|
||||
<local:SettingContainer x:Uid="Globals_CopyFormat">
|
||||
<local:SettingContainer x:Name="CopyFormat"
|
||||
x:Uid="Globals_CopyFormat">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.CopyFormatList, Mode=OneWay}"
|
||||
@@ -42,19 +44,22 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Trim Block Selection -->
|
||||
<local:SettingContainer x:Uid="Globals_TrimBlockSelection">
|
||||
<local:SettingContainer x:Name="TrimBlockSelection"
|
||||
x:Uid="Globals_TrimBlockSelection">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimBlockSelection, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Trim Paste -->
|
||||
<local:SettingContainer x:Uid="Globals_TrimPaste">
|
||||
<local:SettingContainer x:Name="TrimPaste"
|
||||
x:Uid="Globals_TrimPaste">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.TrimPaste, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Word Delimiters -->
|
||||
<local:SettingContainer x:Uid="Globals_WordDelimiters"
|
||||
<local:SettingContainer x:Name="WordDelimiters"
|
||||
x:Uid="Globals_WordDelimiters"
|
||||
CurrentValue="{x:Bind ViewModel.WordDelimiters, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<TextBox IsSpellCheckEnabled="False"
|
||||
@@ -63,13 +68,15 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Snap On Resize -->
|
||||
<local:SettingContainer x:Uid="Globals_SnapToGridOnResize">
|
||||
<local:SettingContainer x:Name="SnapToGridOnResize"
|
||||
x:Uid="Globals_SnapToGridOnResize">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SnapToGridOnResize, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Tab Switcher Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_TabSwitcherMode">
|
||||
<local:SettingContainer x:Name="TabSwitcherMode"
|
||||
x:Uid="Globals_TabSwitcherMode">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.TabSwitcherModeList}"
|
||||
@@ -78,31 +85,36 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Focus Follow Mouse Mode -->
|
||||
<local:SettingContainer x:Uid="Globals_FocusFollowMouse">
|
||||
<local:SettingContainer x:Name="FocusFollowMouse"
|
||||
x:Uid="Globals_FocusFollowMouse">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.FocusFollowMouse, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Enable Font Size Changes with Scrolling -->
|
||||
<local:SettingContainer x:Uid="Globals_ScrollToZoom">
|
||||
<local:SettingContainer x:Name="ScrollToZoom"
|
||||
x:Uid="Globals_ScrollToZoom">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToZoom, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Enable Window Opacity Changes with Scrolling -->
|
||||
<local:SettingContainer x:Uid="Globals_ScrollToChangeOpacity">
|
||||
<local:SettingContainer x:Name="ScrollToChangeOpacity"
|
||||
x:Uid="Globals_ScrollToChangeOpacity">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ScrollToChangeOpacity, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Detect URLs -->
|
||||
<local:SettingContainer x:Uid="Globals_DetectURLs">
|
||||
<local:SettingContainer x:Name="DetectURLs"
|
||||
x:Uid="Globals_DetectURLs">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.DetectURLs, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Search Web Default Query URL -->
|
||||
<local:SettingContainer x:Uid="Globals_SearchWebDefaultQueryUrl"
|
||||
<local:SettingContainer x:Name="SearchWebDefaultQueryUrl"
|
||||
x:Uid="Globals_SearchWebDefaultQueryUrl"
|
||||
CurrentValue="{x:Bind ViewModel.SearchWebDefaultQueryUrl, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<TextBox IsSpellCheckEnabled="False"
|
||||
@@ -111,7 +123,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Enable Color Selection -->
|
||||
<local:SettingContainer x:Uid="Globals_EnableColorSelection">
|
||||
<local:SettingContainer x:Name="EnableColorSelection"
|
||||
x:Uid="Globals_EnableColorSelection">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.EnableColorSelection, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
@@ -123,25 +136,29 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Close All Tabs Warning -->
|
||||
<local:SettingContainer x:Uid="Globals_ConfirmCloseAllTabs">
|
||||
<local:SettingContainer x:Name="ConfirmCloseAllTabs"
|
||||
x:Uid="Globals_ConfirmCloseAllTabs">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ConfirmCloseAllTabs, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Input Service Warning -->
|
||||
<local:SettingContainer x:Uid="Globals_InputServiceWarning">
|
||||
<local:SettingContainer x:Name="InputServiceWarning"
|
||||
x:Uid="Globals_InputServiceWarning">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.InputServiceWarning, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Large Paste Warning -->
|
||||
<local:SettingContainer x:Uid="Globals_WarnAboutLargePaste">
|
||||
<local:SettingContainer x:Name="WarnAboutLargePaste"
|
||||
x:Uid="Globals_WarnAboutLargePaste">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.WarnAboutLargePaste, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Multi Line Paste Warning -->
|
||||
<local:SettingContainer x:Uid="Globals_WarnAboutMultiLinePaste">
|
||||
<local:SettingContainer x:Name="WarnAboutMultiLinePaste"
|
||||
x:Uid="Globals_WarnAboutMultiLinePaste">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind WarnAboutMultiLinePasteList}"
|
||||
|
||||
@@ -38,7 +38,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Launch::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::LaunchViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::LaunchViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
auto innerViewModel{ winrt::get_self<Editor::implementation::LaunchViewModel>(_ViewModel) };
|
||||
/* coroutine dispatch */ innerViewModel->PrepareStartOnUserLoginSettings();
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@
|
||||
<StackPanel>
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Default Profile -->
|
||||
<local:SettingContainer x:Uid="Globals_DefaultProfile">
|
||||
<ComboBox x:Name="DefaultProfile"
|
||||
ItemsSource="{x:Bind ViewModel.DefaultProfiles}"
|
||||
<local:SettingContainer x:Name="DefaultProfile"
|
||||
x:Uid="Globals_DefaultProfile">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.DefaultProfiles}"
|
||||
SelectedItem="{x:Bind ViewModel.CurrentDefaultProfile, Mode=TwoWay}"
|
||||
Style="{StaticResource ComboBoxSettingStyle}">
|
||||
<ComboBox.ItemTemplate>
|
||||
@@ -141,7 +141,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Language -->
|
||||
<local:SettingContainer x:Uid="Globals_Language">
|
||||
<local:SettingContainer x:Name="Language"
|
||||
x:Uid="Globals_Language">
|
||||
<ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
|
||||
SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}"
|
||||
Style="{StaticResource ComboBoxSettingStyle}">
|
||||
@@ -154,7 +155,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Language -->
|
||||
<local:SettingContainer x:Uid="Globals_DefaultInputScope">
|
||||
<local:SettingContainer x:Name="DefaultInputScope"
|
||||
x:Uid="Globals_DefaultInputScope">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.DefaultInputScopeList}"
|
||||
@@ -163,7 +165,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Start on User Login -->
|
||||
<local:SettingContainer x:Uid="Globals_StartOnUserLogin"
|
||||
<local:SettingContainer x:Name="StartOnUserLogin"
|
||||
x:Uid="Globals_StartOnUserLogin"
|
||||
HelpText="{x:Bind ViewModel.StartOnUserLoginStatefulHelpText, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.StartOnUserLoginAvailable, Mode=OneTime}">
|
||||
<ToggleSwitch IsEnabled="{x:Bind ViewModel.StartOnUserLoginConfigurable, Mode=OneWay}"
|
||||
@@ -172,7 +175,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- First Window Behavior -->
|
||||
<local:SettingContainer x:Uid="Globals_FirstWindowPreference">
|
||||
<local:SettingContainer x:Name="FirstWindowPreference"
|
||||
x:Uid="Globals_FirstWindowPreference">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.FirstWindowPreferenceList}"
|
||||
@@ -181,7 +185,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Windowing Behavior -->
|
||||
<local:SettingContainer x:Uid="Globals_WindowingBehavior">
|
||||
<local:SettingContainer x:Name="WindowingBehavior"
|
||||
x:Uid="Globals_WindowingBehavior">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.WindowingBehaviorList}"
|
||||
@@ -190,7 +195,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Launch Size -->
|
||||
<local:SettingContainer x:Uid="Globals_LaunchSize"
|
||||
<local:SettingContainer x:Name="LaunchSize"
|
||||
x:Uid="Globals_LaunchSize"
|
||||
CurrentValue="{x:Bind ViewModel.LaunchSizeCurrentValue, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<Grid ColumnSpacing="12"
|
||||
@@ -233,7 +239,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Launch Parameters -->
|
||||
<local:SettingContainer x:Uid="Globals_LaunchParameters"
|
||||
<local:SettingContainer x:Name="LaunchParameters"
|
||||
x:Uid="Globals_LaunchParameters"
|
||||
CurrentValue="{x:Bind ViewModel.LaunchParametersCurrentValue, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<Grid RowSpacing="8">
|
||||
|
||||
@@ -15,14 +15,18 @@
|
||||
#include "GlobalAppearance.h"
|
||||
#include "GlobalAppearanceViewModel.h"
|
||||
#include "ColorSchemes.h"
|
||||
#include "EditColorScheme.h"
|
||||
#include "AddProfile.h"
|
||||
#include "InteractionViewModel.h"
|
||||
#include "LaunchViewModel.h"
|
||||
#include "NewTabMenuViewModel.h"
|
||||
#include "NewTabMenu.h"
|
||||
#include "NavConstants.h"
|
||||
#include "..\types\inc\utils.hpp"
|
||||
#include <..\WinRTUtils\inc\Utils.h>
|
||||
|
||||
#include <dwmapi.h>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
@@ -38,29 +42,45 @@ using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
|
||||
static const std::wstring_view openJsonTag{ L"OpenJson_Nav" };
|
||||
static const std::wstring_view launchTag{ L"Launch_Nav" };
|
||||
static const std::wstring_view interactionTag{ L"Interaction_Nav" };
|
||||
static const std::wstring_view renderingTag{ L"Rendering_Nav" };
|
||||
static const std::wstring_view compatibilityTag{ L"Compatibility_Nav" };
|
||||
static const std::wstring_view actionsTag{ L"Actions_Nav" };
|
||||
static const std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
|
||||
static const std::wstring_view extensionsTag{ L"Extensions_Nav" };
|
||||
static const std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
|
||||
static const std::wstring_view addProfileTag{ L"AddProfile" };
|
||||
static const std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
|
||||
static const std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" };
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
static WUX::Controls::FontIcon _fontIconForNavTag(const std::wstring_view navTag)
|
||||
{
|
||||
WUX::Controls::FontIcon icon{};
|
||||
icon.Glyph(NavTagIconMap[navTag]);
|
||||
icon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(16);
|
||||
return icon;
|
||||
}
|
||||
|
||||
static Editor::ProfileViewModel _viewModelForProfile(const Model::Profile& profile, const Model::CascadiaSettings& appSettings, const Windows::UI::Core::CoreDispatcher& dispatcher)
|
||||
{
|
||||
return winrt::make<implementation::ProfileViewModel>(profile, appSettings, dispatcher);
|
||||
}
|
||||
|
||||
static ProfileSubPage ProfileSubPageFromBreadcrumb(BreadcrumbSubPage subPage)
|
||||
{
|
||||
switch (subPage)
|
||||
{
|
||||
case BreadcrumbSubPage::None:
|
||||
return ProfileSubPage::Base;
|
||||
case BreadcrumbSubPage::Profile_Appearance:
|
||||
return ProfileSubPage::Appearance;
|
||||
case BreadcrumbSubPage::Profile_Terminal:
|
||||
return ProfileSubPage::Terminal;
|
||||
case BreadcrumbSubPage::Profile_Advanced:
|
||||
return ProfileSubPage::Advanced;
|
||||
default:
|
||||
// This should never happen
|
||||
assert(false);
|
||||
return ProfileSubPage::Base;
|
||||
}
|
||||
}
|
||||
|
||||
MainPage::MainPage(const CascadiaSettings& settings) :
|
||||
_settingsSource{ settings },
|
||||
_settingsClone{ settings.Copy() }
|
||||
_settingsClone{ settings.Copy() },
|
||||
_profileVMs{ single_threaded_observable_vector<Editor::ProfileViewModel>() }
|
||||
{
|
||||
InitializeComponent();
|
||||
_UpdateBackgroundForMica();
|
||||
@@ -92,16 +112,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto settingName{ args.PropertyName() };
|
||||
if (settingName == L"CurrentPage")
|
||||
{
|
||||
// extract ElementToFocus and clear it; we only want to use it once
|
||||
auto vmImpl = get_self<ColorSchemesPageViewModel>(_colorSchemesPageVM);
|
||||
const auto elementToFocus = vmImpl->ElementToFocus();
|
||||
vmImpl->ElementToFocus({});
|
||||
|
||||
const auto currentScheme = _colorSchemesPageVM.CurrentScheme();
|
||||
if (_colorSchemesPageVM.CurrentPage() == ColorSchemesSubPage::EditColorScheme && currentScheme)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditColorScheme>(), currentScheme);
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditColorScheme>(), winrt::make<NavigateToPageArgs>(currentScheme, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(colorSchemesTag), currentScheme.Name(), BreadcrumbSubPage::ColorSchemes_Edit);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
else if (_colorSchemesPageVM.CurrentPage() == ColorSchemesSubPage::Base)
|
||||
{
|
||||
_Navigate(winrt::hstring{ colorSchemesTag }, BreadcrumbSubPage::None);
|
||||
_Navigate(winrt::hstring{ colorSchemesTag }, BreadcrumbSubPage::None, elementToFocus);
|
||||
}
|
||||
}
|
||||
else if (settingName == L"CurrentSchemeName")
|
||||
@@ -141,9 +166,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
if (const auto& currentExtensionPackage = _extensionsVM.CurrentExtensionPackage())
|
||||
{
|
||||
const auto& pkg = currentExtensionPackage.Package();
|
||||
const auto label = pkg.DisplayName().empty() ? pkg.Source() : pkg.DisplayName();
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(currentExtensionPackage), label, BreadcrumbSubPage::Extensions_Extension);
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(currentExtensionPackage), currentExtensionPackage.DisplayName(), BreadcrumbSubPage::Extensions_Extension);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
}
|
||||
@@ -154,7 +177,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(extensionsTag), RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), _extensionsVM);
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -162,6 +185,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// that VM into the appearance VMs within the profiles
|
||||
_InitializeProfilesList();
|
||||
|
||||
// Apply icons to static nav items
|
||||
LaunchNavItem().Icon(_fontIconForNavTag(launchTag));
|
||||
InteractionNavItem().Icon(_fontIconForNavTag(interactionTag));
|
||||
AppearanceNavItem().Icon(_fontIconForNavTag(globalAppearanceTag));
|
||||
ColorSchemesNavItem().Icon(_fontIconForNavTag(colorSchemesTag));
|
||||
RenderingNavItem().Icon(_fontIconForNavTag(renderingTag));
|
||||
CompatibilityNavItem().Icon(_fontIconForNavTag(compatibilityTag));
|
||||
ActionsNavItem().Icon(_fontIconForNavTag(actionsTag));
|
||||
NewTabMenuNavItem().Icon(_fontIconForNavTag(newTabMenuTag));
|
||||
ExtensionsNavItem().Icon(_fontIconForNavTag(extensionsTag));
|
||||
BaseLayerMenuItem().Icon(_fontIconForNavTag(globalProfileTag));
|
||||
OpenJsonNavItem().Icon(_fontIconForNavTag(openJsonTag));
|
||||
|
||||
Automation::AutomationProperties::SetHelpText(SaveButton(), RS_(L"Settings_SaveSettingsButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
Automation::AutomationProperties::SetHelpText(ResetButton(), RS_(L"Settings_ResetSettingsButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
Automation::AutomationProperties::SetHelpText(OpenJsonNavItem(), RS_(L"Nav_OpenJSON/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"));
|
||||
@@ -180,6 +216,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
WUX::Controls::ToolTipService::SetToolTip(OpenJsonNavItem(), box_value(RS_(L"Nav_OpenJSON/Content")));
|
||||
|
||||
_breadcrumbs = single_threaded_observable_vector<IInspectable>();
|
||||
_UpdateSearchIndex();
|
||||
extensionsVMImpl->LazyLoadExtensions();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -218,11 +256,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
// Repopulate profile-related menu items
|
||||
_InitializeProfilesList();
|
||||
|
||||
// Update the Nav State with the new version of the settings
|
||||
_colorSchemesPageVM.UpdateSettings(_settingsClone);
|
||||
_actionsVM.UpdateSettings(_settingsClone);
|
||||
_newTabMenuPageVM.UpdateSettings(_settingsClone);
|
||||
_extensionsVM.UpdateSettings(_settingsClone, _colorSchemesPageVM);
|
||||
_profileDefaultsVM = nullptr; // Lazy-loaded upon navigation
|
||||
|
||||
// We'll update the profile in the _profilesNavState whenever we actually navigate to one
|
||||
|
||||
@@ -243,8 +283,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (stringTag == breadcrumbStringTag)
|
||||
{
|
||||
// found the one that was selected before the refresh
|
||||
SettingsNav().SelectedItem(item);
|
||||
_Navigate(*breadcrumbStringTag, crumb->SubPage());
|
||||
SettingsNav().SelectedItem(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -254,8 +294,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
// navigate to the NewTabMenu page,
|
||||
// _Navigate() will handle trying to find the right subpage
|
||||
SettingsNav().SelectedItem(item);
|
||||
_Navigate(breadcrumbFolderEntry, BreadcrumbSubPage::NewTabMenu_Folder);
|
||||
SettingsNav().SelectedItem(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -265,8 +305,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
// navigate to the Extensions page,
|
||||
// _Navigate() will handle trying to find the right subpage
|
||||
SettingsNav().SelectedItem(item);
|
||||
_Navigate(breadcrumbExtensionPackage, BreadcrumbSubPage::Extensions_Extension);
|
||||
SettingsNav().SelectedItem(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -278,8 +318,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (profileTag->OriginalProfileGuid() == breadcrumbProfileTag->OriginalProfileGuid())
|
||||
{
|
||||
// found the one that was selected before the refresh
|
||||
SettingsNav().SelectedItem(item);
|
||||
_Navigate(*profileTag, crumb->SubPage());
|
||||
SettingsNav().SelectedItem(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -293,8 +333,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// This happens when the selected item was a profile which doesn't exist in the new configuration
|
||||
// We can use menuItemsSTL here because the only things they miss are profile entries.
|
||||
const auto& firstItem{ _menuItemSource.GetAt(0).as<MUX::Controls::NavigationViewItem>() };
|
||||
SettingsNav().SelectedItem(firstItem);
|
||||
_Navigate(unbox_value<hstring>(firstItem.Tag()), BreadcrumbSubPage::None);
|
||||
SettingsNav().SelectedItem(firstItem);
|
||||
|
||||
_UpdateSearchIndex();
|
||||
}
|
||||
|
||||
void MainPage::SetHostingWindow(uint64_t hostingWindow) noexcept
|
||||
@@ -455,31 +497,37 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto settingName{ args.PropertyName() };
|
||||
if (settingName == L"CurrentPage")
|
||||
{
|
||||
// extract ElementToFocus and clear it; we only want to use it once
|
||||
auto vmImpl = get_self<ProfileViewModel>(profile);
|
||||
const auto elementToFocus = vmImpl->ElementToFocus();
|
||||
vmImpl->ElementToFocus({});
|
||||
|
||||
const auto currentPage = profile.CurrentPage();
|
||||
if (currentPage == ProfileSubPage::Base)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
_breadcrumbs.Clear();
|
||||
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, breadcrumbText, BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
}
|
||||
else if (currentPage == ProfileSubPage::Appearance)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Appearance>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Appearance/Header"), BreadcrumbSubPage::Profile_Appearance);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
}
|
||||
else if (currentPage == ProfileSubPage::Terminal)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Terminal>(), profile);
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Terminal>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Terminal/Header"), BreadcrumbSubPage::Profile_Terminal);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
}
|
||||
else if (currentPage == ProfileSubPage::Advanced)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Advanced/Header"), BreadcrumbSubPage::Profile_Advanced);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
|
||||
@@ -488,39 +536,44 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
});
|
||||
}
|
||||
|
||||
void MainPage::_Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage)
|
||||
void MainPage::_Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage, hstring elementToFocus)
|
||||
{
|
||||
_PreNavigateHelper();
|
||||
|
||||
if (clickedItemTag == launchTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Launch>(), winrt::make<LaunchViewModel>(_settingsClone));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Launch>(), winrt::make<NavigateToPageArgs>(winrt::make<LaunchViewModel>(_settingsClone), *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Launch/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(LaunchNavItem());
|
||||
}
|
||||
else if (clickedItemTag == interactionTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Interaction>(), winrt::make<InteractionViewModel>(_settingsClone.GlobalSettings()));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Interaction>(), winrt::make<NavigateToPageArgs>(winrt::make<InteractionViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Interaction/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(InteractionNavItem());
|
||||
}
|
||||
else if (clickedItemTag == renderingTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Rendering>(), winrt::make<RenderingViewModel>(_settingsClone));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Rendering>(), winrt::make<NavigateToPageArgs>(winrt::make<RenderingViewModel>(_settingsClone), *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Rendering/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(RenderingNavItem());
|
||||
}
|
||||
else if (clickedItemTag == compatibilityTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Compatibility>(), winrt::make<CompatibilityViewModel>(_settingsClone));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Compatibility>(), winrt::make<NavigateToPageArgs>(winrt::make<CompatibilityViewModel>(_settingsClone), *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Compatibility/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(CompatibilityNavItem());
|
||||
}
|
||||
else if (clickedItemTag == actionsTag)
|
||||
{
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Actions/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), _actionsVM);
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<NavigateToPageArgs>(_actionsVM, *this, elementToFocus));
|
||||
SettingsNav().SelectedItem(ActionsNavItem());
|
||||
|
||||
if (subPage == BreadcrumbSubPage::Actions_Edit && _actionsVM.CurrentCommand() != nullptr)
|
||||
{
|
||||
@@ -538,10 +591,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
else
|
||||
{
|
||||
// Navigate to the NewTabMenu page
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_NewTabMenu/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
SettingsNav().SelectedItem(NewTabMenuNavItem());
|
||||
}
|
||||
else if (clickedItemTag == extensionsTag)
|
||||
{
|
||||
@@ -553,42 +607,52 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), _extensionsVM);
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
}
|
||||
SettingsNav().SelectedItem(ExtensionsNavItem());
|
||||
}
|
||||
else if (clickedItemTag == globalProfileTag)
|
||||
{
|
||||
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone, Dispatcher()) };
|
||||
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
profileVM.IsBaseLayer(true);
|
||||
// lazy load profile defaults VM
|
||||
if (!_profileDefaultsVM)
|
||||
{
|
||||
_profileDefaultsVM = _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone, Dispatcher());
|
||||
_profileDefaultsVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
|
||||
_profileDefaultsVM.IsBaseLayer(true);
|
||||
}
|
||||
|
||||
_SetupProfileEventHandling(profileVM);
|
||||
_SetupProfileEventHandling(_profileDefaultsVM);
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profileVM, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<NavigateToPageArgs>(_profileDefaultsVM, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_ProfileDefaults/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(BaseLayerMenuItem());
|
||||
|
||||
// If we were given a label, make sure we are on the correct sub-page
|
||||
if (subPage == BreadcrumbSubPage::Profile_Appearance)
|
||||
// Pass along the element to focus to the ProfileViewModel.
|
||||
// This will work as a staging area before we navigate to the correct sub-page
|
||||
auto profileVMImpl = get_self<ProfileViewModel>(_profileDefaultsVM);
|
||||
profileVMImpl->ElementToFocus(elementToFocus);
|
||||
|
||||
// Set the profile's 'CurrentPage' to the correct one, if this requires further navigation, the
|
||||
// event handler will do it
|
||||
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
|
||||
const bool needsForcedRefresh = _profileDefaultsVM.CurrentPage() == profileSubPage;
|
||||
_profileDefaultsVM.CurrentPage(profileSubPage);
|
||||
if (needsForcedRefresh)
|
||||
{
|
||||
profileVM.CurrentPage(ProfileSubPage::Appearance);
|
||||
}
|
||||
else if (subPage == BreadcrumbSubPage::Profile_Terminal)
|
||||
{
|
||||
profileVM.CurrentPage(ProfileSubPage::Terminal);
|
||||
}
|
||||
else if (subPage == BreadcrumbSubPage::Profile_Advanced)
|
||||
{
|
||||
profileVM.CurrentPage(ProfileSubPage::Advanced);
|
||||
// If we're already on the correct sub-page, the PropertyChanged event won't fire.
|
||||
// However, we still need to pass along the ElementToFocus, so we need to force a refresh.
|
||||
profileVMImpl->ForceRefreshCurrentPage();
|
||||
}
|
||||
}
|
||||
else if (clickedItemTag == colorSchemesTag)
|
||||
{
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), _colorSchemesPageVM);
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus));
|
||||
SettingsNav().SelectedItem(ColorSchemesNavItem());
|
||||
|
||||
if (subPage == BreadcrumbSubPage::ColorSchemes_Edit)
|
||||
{
|
||||
@@ -597,17 +661,39 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
else if (clickedItemTag == globalAppearanceTag)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::GlobalAppearance>(), winrt::make<GlobalAppearanceViewModel>(_settingsClone.GlobalSettings()));
|
||||
contentFrame().Navigate(xaml_typename<Editor::GlobalAppearance>(), winrt::make<NavigateToPageArgs>(winrt::make<GlobalAppearanceViewModel>(_settingsClone.GlobalSettings()), *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_Appearance/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(AppearanceNavItem());
|
||||
}
|
||||
else if (clickedItemTag == addProfileTag)
|
||||
{
|
||||
auto addProfileState{ winrt::make<AddProfilePageNavigationState>(_settingsClone) };
|
||||
auto addProfileState{ winrt::make<AddProfilePageNavigationState>(_settingsClone, elementToFocus) };
|
||||
addProfileState.AddNew({ get_weak(), &MainPage::_AddProfileHandler });
|
||||
contentFrame().Navigate(xaml_typename<Editor::AddProfile>(), addProfileState);
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_AddNewProfile/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
|
||||
// Find the "Add new profile" menu item and select it
|
||||
// It's likely at the very end of the list, so we'll search backwards
|
||||
for (auto i = _menuItemSource.Size() - 1; i > 0; --i)
|
||||
{
|
||||
const auto& item = _menuItemSource.GetAt(i);
|
||||
if (const auto& menuItem{ item.try_as<MUX::Controls::NavigationViewItem>() })
|
||||
{
|
||||
if (const auto& tag{ menuItem.Tag() })
|
||||
{
|
||||
if (const auto& stringTag{ tag.try_as<hstring>() })
|
||||
{
|
||||
if (*stringTag == addProfileTag)
|
||||
{
|
||||
SettingsNav().SelectedItem(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,7 +702,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// - NOTE: this does not update the selected item.
|
||||
// Arguments:
|
||||
// - profile - the profile object we are getting a view of
|
||||
void MainPage::_Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage)
|
||||
void MainPage::_Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage, hstring elementToFocus)
|
||||
{
|
||||
_PreNavigateHelper();
|
||||
|
||||
@@ -624,44 +710,74 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
if (profile.Orphaned())
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base_Orphaned>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base_Orphaned>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(profile), profile.Name(), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
profile.CurrentPage(ProfileSubPage::Base);
|
||||
return;
|
||||
}
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
|
||||
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<NavigateToPageArgs>(profile, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(profile), profile.Name(), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
if (const auto profileNavItem = _FindProfileNavItem(profile.OriginalProfileGuid()))
|
||||
{
|
||||
SettingsNav().SelectedItem(profileNavItem);
|
||||
}
|
||||
|
||||
// Pass along the element to focus to the ProfileViewModel.
|
||||
// This will work as a staging area before we navigate to the correct sub-page
|
||||
auto profileVMImpl = get_self<ProfileViewModel>(profile);
|
||||
profileVMImpl->ElementToFocus(elementToFocus);
|
||||
|
||||
// Set the profile's 'CurrentPage' to the correct one, if this requires further navigation, the
|
||||
// event handler will do it
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
|
||||
const bool needsForcedRefresh = profile.CurrentPage() == profileSubPage;
|
||||
profile.CurrentPage(profileSubPage);
|
||||
if (needsForcedRefresh)
|
||||
{
|
||||
profile.CurrentPage(ProfileSubPage::Base);
|
||||
}
|
||||
else if (subPage == BreadcrumbSubPage::Profile_Appearance)
|
||||
{
|
||||
profile.CurrentPage(ProfileSubPage::Appearance);
|
||||
}
|
||||
else if (subPage == BreadcrumbSubPage::Profile_Terminal)
|
||||
{
|
||||
profile.CurrentPage(ProfileSubPage::Terminal);
|
||||
}
|
||||
else if (subPage == BreadcrumbSubPage::Profile_Advanced)
|
||||
{
|
||||
profile.CurrentPage(ProfileSubPage::Advanced);
|
||||
// If we're already on the correct sub-page, the PropertyChanged event won't fire.
|
||||
// However, we still need to pass along the ElementToFocus, so we need to force a refresh.
|
||||
profileVMImpl->ForceRefreshCurrentPage();
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_Navigate(const Editor::NewTabMenuEntryViewModel& ntmEntryVM, BreadcrumbSubPage subPage)
|
||||
void MainPage::_Navigate(const Editor::ColorSchemeViewModel& colorSchemeVM, BreadcrumbSubPage subPage, hstring elementToFocus)
|
||||
{
|
||||
_PreNavigateHelper();
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(colorSchemesTag), RS_(L"Nav_ColorSchemes/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
contentFrame().Navigate(xaml_typename<Editor::ColorSchemes>(), winrt::make<NavigateToPageArgs>(_colorSchemesPageVM, *this, elementToFocus));
|
||||
SettingsNav().SelectedItem(ColorSchemesNavItem());
|
||||
|
||||
// Pass along the element to focus to the ColorSchemesPageViewModel.
|
||||
// This will work as a staging area before we navigate to EditColorScheme
|
||||
get_self<ColorSchemesPageViewModel>(_colorSchemesPageVM)->ElementToFocus(elementToFocus);
|
||||
|
||||
// Set CurrentScheme BEFORE the CurrentPage!
|
||||
// Doing so triggers the PropertyChanged event which performs the navigation to EditColorScheme
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
{
|
||||
_colorSchemesPageVM.CurrentScheme(nullptr);
|
||||
_colorSchemesPageVM.CurrentPage(ColorSchemesSubPage::Base);
|
||||
}
|
||||
else
|
||||
{
|
||||
_colorSchemesPageVM.CurrentScheme(colorSchemeVM);
|
||||
_colorSchemesPageVM.CurrentPage(ColorSchemesSubPage::EditColorScheme);
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_Navigate(const Editor::NewTabMenuEntryViewModel& ntmEntryVM, BreadcrumbSubPage subPage, hstring elementToFocus)
|
||||
{
|
||||
_PreNavigateHelper();
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::NewTabMenu>(), winrt::make<NavigateToPageArgs>(_newTabMenuPageVM, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(newTabMenuTag), RS_(L"Nav_NewTabMenu/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(NewTabMenuNavItem());
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
{
|
||||
@@ -688,13 +804,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_Navigate(const Editor::ExtensionPackageViewModel& extPkgVM, BreadcrumbSubPage subPage)
|
||||
void MainPage::_Navigate(const Editor::ExtensionPackageViewModel& extPkgVM, BreadcrumbSubPage subPage, hstring elementToFocus)
|
||||
{
|
||||
_PreNavigateHelper();
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), _extensionsVM);
|
||||
contentFrame().Navigate(xaml_typename<Editor::Extensions>(), winrt::make<NavigateToPageArgs>(_extensionsVM, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(extensionsTag), RS_(L"Nav_Extensions/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(ExtensionsNavItem());
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None)
|
||||
{
|
||||
@@ -708,9 +825,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
if (pkgVM.Package().Source() == extPkgVM.Package().Source())
|
||||
{
|
||||
// Take advantage of the PropertyChanged event to navigate
|
||||
// to the correct extension package and build the breadcrumbs as we go
|
||||
// to the correct extension package and build the breadcrumbs as we go.
|
||||
const auto wasAlreadyOnExtension = (_extensionsVM.CurrentExtensionPackage() == pkgVM);
|
||||
_extensionsVM.CurrentExtensionPackage(pkgVM);
|
||||
found = true;
|
||||
|
||||
// If CurrentExtensionPackage was already this extension, PropertyChanged won't fire,
|
||||
// so we add the breadcrumb manually.
|
||||
if (wasAlreadyOnExtension)
|
||||
{
|
||||
const auto extCrumb = winrt::make<Breadcrumb>(box_value(pkgVM), pkgVM.DisplayName(), BreadcrumbSubPage::Extensions_Extension);
|
||||
_breadcrumbs.Append(extCrumb);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -722,6 +848,38 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::_Navigate(const Editor::CommandViewModel& commandVM, BreadcrumbSubPage subPage, hstring elementToFocus)
|
||||
{
|
||||
_PreNavigateHelper();
|
||||
|
||||
contentFrame().Navigate(xaml_typename<Editor::Actions>(), winrt::make<NavigateToPageArgs>(_actionsVM, *this, elementToFocus));
|
||||
const auto crumb = winrt::make<Breadcrumb>(box_value(actionsTag), RS_(L"Nav_Actions/Content"), BreadcrumbSubPage::None);
|
||||
_breadcrumbs.Append(crumb);
|
||||
SettingsNav().SelectedItem(ActionsNavItem());
|
||||
|
||||
if (subPage == BreadcrumbSubPage::None || !commandVM)
|
||||
{
|
||||
_actionsVM.CurrentCommand(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take advantage of the PropertyChanged event to navigate
|
||||
// to EditAction and build the breadcrumbs as we go.
|
||||
const auto wasAlreadyEdit = (_actionsVM.CurrentPage() == ActionsSubPage::Edit);
|
||||
_actionsVM.CurrentCommand(commandVM);
|
||||
_actionsVM.CurrentPage(ActionsSubPage::Edit);
|
||||
|
||||
// If CurrentPage was already Edit, PropertyChanged won't fire,
|
||||
// so we navigate and add breadcrumb manually.
|
||||
if (wasAlreadyEdit)
|
||||
{
|
||||
contentFrame().Navigate(xaml_typename<Editor::EditAction>(), winrt::make<implementation::NavigateToCommandArgs>(commandVM, *this));
|
||||
const auto editCrumb = winrt::make<Breadcrumb>(box_value(actionsTag), RS_(L"Nav_EditAction/Content"), BreadcrumbSubPage::Actions_Edit);
|
||||
_breadcrumbs.Append(editCrumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::SaveButton_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*args*/)
|
||||
{
|
||||
_settingsClone.LogSettingChanges(false);
|
||||
@@ -774,10 +932,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_MoveXamlParsedNavItemsIntoItemSource();
|
||||
}
|
||||
|
||||
// Manually create a NavigationViewItem for each profile
|
||||
// Manually create a NavigationViewItem and view model for each profile
|
||||
// and keep a reference to them in a map so that we
|
||||
// can easily modify the correct one when the associated
|
||||
// profile changes.
|
||||
_profileVMs.Clear();
|
||||
for (const auto& profile : _settingsClone.AllProfiles())
|
||||
{
|
||||
if (!profile.Deleted())
|
||||
@@ -798,7 +957,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
FontIcon icon;
|
||||
// This is the "Add" symbol
|
||||
icon.Glyph(L"\xE710");
|
||||
icon.Glyph(NavTagIconMap[addProfileTag]);
|
||||
addProfileItem.Icon(icon);
|
||||
|
||||
_menuItemSource.Append(addProfileItem);
|
||||
@@ -850,8 +1009,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
|
||||
// Select and navigate to the new profile
|
||||
SettingsNav().SelectedItem(navItem);
|
||||
_Navigate(profileViewModel, BreadcrumbSubPage::None);
|
||||
SettingsNav().SelectedItem(navItem);
|
||||
}
|
||||
|
||||
static MUX::Controls::InfoBadge _createGlyphIconBadge(wil::zwstring_view glyph)
|
||||
@@ -907,6 +1066,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// Add an event handler for when the user wants to delete a profile.
|
||||
profile.DeleteProfileRequested({ this, &MainPage::_DeleteProfile });
|
||||
|
||||
// Register the VM so that it appears in the search index
|
||||
_profileVMs.Append(profile);
|
||||
|
||||
return profileNavItem;
|
||||
}
|
||||
|
||||
@@ -932,9 +1094,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
_menuItemSource.IndexOf(selectedItem, index);
|
||||
_menuItemSource.RemoveAt(index);
|
||||
|
||||
// Remove it from the list of VMs
|
||||
auto profileVM = selectedItem.as<MUX::Controls::NavigationViewItem>().Tag().as<Editor::ProfileViewModel>();
|
||||
uint32_t vmIndex;
|
||||
if (_menuItemSource.IndexOf(profileVM, vmIndex))
|
||||
{
|
||||
_profileVMs.RemoveAt(vmIndex);
|
||||
}
|
||||
|
||||
// navigate to the profile next to this one
|
||||
const auto newSelectedItem{ _menuItemSource.GetAt(index < _menuItemSource.Size() - 1 ? index : index - 1) };
|
||||
SettingsNav().SelectedItem(newSelectedItem);
|
||||
const auto newTag = newSelectedItem.as<MUX::Controls::NavigationViewItem>().Tag();
|
||||
if (const auto profileViewModel = newTag.try_as<ProfileViewModel>())
|
||||
{
|
||||
@@ -947,6 +1116,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
// Since we are navigating to a new profile after deletion, scroll up to the top
|
||||
SettingsMainPage_ScrollViewer().ChangeView(nullptr, 0.0, nullptr);
|
||||
SettingsNav().SelectedItem(newSelectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,6 +1126,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
|
||||
void MainPage::_NavigateToProfileHandler(const IInspectable& /*sender*/, winrt::guid profileGuid)
|
||||
{
|
||||
if (const auto profileNavItem = _FindProfileNavItem(profileGuid))
|
||||
{
|
||||
_Navigate(profileNavItem.Tag().as<Editor::ProfileViewModel>(), BreadcrumbSubPage::None);
|
||||
}
|
||||
// Silently fail if the profile wasn't found
|
||||
}
|
||||
|
||||
MUX::Controls::NavigationViewItem MainPage::_FindProfileNavItem(winrt::guid profileGuid) const
|
||||
{
|
||||
for (auto&& menuItem : _menuItemSource)
|
||||
{
|
||||
@@ -967,21 +1146,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
if (profileTag->OriginalProfileGuid() == profileGuid)
|
||||
{
|
||||
SettingsNav().SelectedItem(menuItem);
|
||||
_Navigate(*profileTag, BreadcrumbSubPage::None);
|
||||
return;
|
||||
return navViewItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Silently fail if the profile wasn't found
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MainPage::_NavigateToColorSchemeHandler(const IInspectable& /*sender*/, const IInspectable& /*args*/)
|
||||
{
|
||||
SettingsNav().SelectedItem(ColorSchemesNavItem());
|
||||
_Navigate(hstring{ colorSchemesTag }, BreadcrumbSubPage::ColorSchemes_Edit);
|
||||
SettingsNav().SelectedItem(ColorSchemesNavItem());
|
||||
}
|
||||
|
||||
winrt::Windows::UI::Xaml::Media::Brush MainPage::BackgroundBrush()
|
||||
@@ -1045,4 +1222,121 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
}
|
||||
}
|
||||
|
||||
safe_void_coroutine MainPage::SettingsSearchBox_TextChanged(const AutoSuggestBox& sender, const AutoSuggestBoxTextChangedEventArgs& args)
|
||||
{
|
||||
if (args.Reason() != AutoSuggestionBoxTextChangeReason::UserInput)
|
||||
{
|
||||
// Only respond to user input, not programmatic text changes
|
||||
co_return;
|
||||
}
|
||||
|
||||
// remove leading spaces
|
||||
std::wstring queryW{ sender.Text() };
|
||||
const auto firstNonSpace{ queryW.find_first_not_of(L' ') };
|
||||
if (firstNonSpace == std::wstring::npos)
|
||||
{
|
||||
// only spaces
|
||||
const auto& searchBox = SettingsSearchBox();
|
||||
searchBox.ItemsSource(nullptr);
|
||||
searchBox.IsSuggestionListOpen(false);
|
||||
co_return;
|
||||
}
|
||||
|
||||
const hstring sanitizedQuery{ queryW.substr(firstNonSpace) };
|
||||
if (sanitizedQuery.empty())
|
||||
{
|
||||
// empty query
|
||||
const auto& searchBox = SettingsSearchBox();
|
||||
searchBox.ItemsSource(nullptr);
|
||||
searchBox.IsSuggestionListOpen(false);
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (_currentSearch)
|
||||
{
|
||||
// a newer search has started, abandon this one
|
||||
_currentSearch.Cancel();
|
||||
co_return;
|
||||
}
|
||||
_currentSearch = SearchIndex::Instance().SearchAsync(sanitizedQuery,
|
||||
_profileVMs.GetView(),
|
||||
get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList().GetView(),
|
||||
_colorSchemesPageVM.AllColorSchemes().GetView(),
|
||||
_extensionsVM.ExtensionPackages().GetView(),
|
||||
_actionsVM.CommandList().GetView());
|
||||
const auto results = co_await _currentSearch;
|
||||
_currentSearch = nullptr;
|
||||
|
||||
// Update the UI with the results
|
||||
const auto& searchBox = SettingsSearchBox();
|
||||
searchBox.ItemsSource(results);
|
||||
searchBox.IsSuggestionListOpen(true);
|
||||
}
|
||||
|
||||
void MainPage::SettingsSearchBox_QuerySubmitted(const AutoSuggestBox& /*sender*/, const AutoSuggestBoxQuerySubmittedEventArgs& args)
|
||||
{
|
||||
if (args.ChosenSuggestion())
|
||||
{
|
||||
const auto& chosenResult{ args.ChosenSuggestion().as<FilteredSearchResult>() };
|
||||
if (chosenResult->IsNoResultsPlaceholder())
|
||||
{
|
||||
// don't navigate anywhere
|
||||
return;
|
||||
}
|
||||
|
||||
// Navigate to the target page
|
||||
const auto& indexEntry{ chosenResult->SearchIndexEntry() };
|
||||
const auto& navigationArg{ chosenResult->NavigationArg() };
|
||||
const auto& subpage{ indexEntry.Entry->SubPage };
|
||||
const auto& elementToFocus{ indexEntry.Entry->ElementName };
|
||||
if (const auto navArgString = navigationArg.try_as<hstring>())
|
||||
{
|
||||
_Navigate(*navArgString, subpage, elementToFocus);
|
||||
}
|
||||
else if (const auto& profileVM = navigationArg.try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
_Navigate(profileVM, subpage, elementToFocus);
|
||||
}
|
||||
else if (const auto& colorSchemeVM = navigationArg.try_as<Editor::ColorSchemeViewModel>())
|
||||
{
|
||||
_Navigate(colorSchemeVM, subpage, elementToFocus);
|
||||
}
|
||||
else if (const auto& ntmEntryVM = navigationArg.try_as<Editor::NewTabMenuEntryViewModel>())
|
||||
{
|
||||
_Navigate(ntmEntryVM, subpage, elementToFocus);
|
||||
}
|
||||
else if (const auto& extPkgVM = navigationArg.try_as<Editor::ExtensionPackageViewModel>())
|
||||
{
|
||||
_Navigate(extPkgVM, subpage, elementToFocus);
|
||||
}
|
||||
else if (const auto& commandVM = navigationArg.try_as<Editor::CommandViewModel>())
|
||||
{
|
||||
_Navigate(commandVM, subpage, elementToFocus);
|
||||
}
|
||||
SettingsSearchBox().Text(L"");
|
||||
}
|
||||
}
|
||||
|
||||
void MainPage::SettingsSearchBox_SuggestionChosen(const AutoSuggestBox&, const AutoSuggestBoxSuggestionChosenEventArgs&)
|
||||
{
|
||||
// Don't navigate on arrow keys
|
||||
// Handle Enter/Click with QuerySubmitted() to instead
|
||||
// AutoSuggestBox will pass the chosen item to QuerySubmitted() via args.ChosenSuggestion()
|
||||
}
|
||||
|
||||
safe_void_coroutine MainPage::_UpdateSearchIndex()
|
||||
{
|
||||
auto weakThis = get_weak();
|
||||
|
||||
co_await winrt::resume_background();
|
||||
|
||||
if (auto strongThis = weakThis.get())
|
||||
{
|
||||
if (strongThis->_currentSearch && strongThis->_currentSearch.Status() == AsyncStatus::Started)
|
||||
{
|
||||
strongThis->_currentSearch.Cancel();
|
||||
}
|
||||
SearchIndex::Instance().Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Breadcrumb.g.h"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "Utils.h"
|
||||
#include "SearchIndex.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
@@ -27,16 +28,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
struct NavigateToPageArgs : NavigateToPageArgsT<NavigateToPageArgs>
|
||||
{
|
||||
public:
|
||||
NavigateToPageArgs(Windows::Foundation::IInspectable viewModel, Editor::IHostedInWindow windowRoot) :
|
||||
NavigateToPageArgs(Windows::Foundation::IInspectable viewModel, Editor::IHostedInWindow windowRoot, const hstring& elementToFocus = {}) :
|
||||
_ViewModel(viewModel),
|
||||
_WeakWindowRoot(windowRoot) {}
|
||||
_WeakWindowRoot(windowRoot),
|
||||
_ElementToFocus(elementToFocus) {}
|
||||
|
||||
Editor::IHostedInWindow WindowRoot() const noexcept { return _WeakWindowRoot.get(); }
|
||||
Windows::Foundation::IInspectable ViewModel() const noexcept { return _ViewModel; }
|
||||
hstring ElementToFocus() const noexcept { return _ElementToFocus; }
|
||||
|
||||
private:
|
||||
winrt::weak_ref<Editor::IHostedInWindow> _WeakWindowRoot{ nullptr };
|
||||
winrt::weak_ref<Editor::IHostedInWindow> _WeakWindowRoot;
|
||||
Windows::Foundation::IInspectable _ViewModel{ nullptr };
|
||||
hstring _ElementToFocus{};
|
||||
};
|
||||
|
||||
struct MainPage : MainPageT<MainPage>
|
||||
@@ -46,6 +50,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void UpdateSettings(const Model::CascadiaSettings& settings);
|
||||
|
||||
safe_void_coroutine SettingsSearchBox_TextChanged(const Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxTextChangedEventArgs& args);
|
||||
void SettingsSearchBox_QuerySubmitted(const Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxQuerySubmittedEventArgs& args);
|
||||
void SettingsSearchBox_SuggestionChosen(const Windows::UI::Xaml::Controls::AutoSuggestBox& sender, const Windows::UI::Xaml::Controls::AutoSuggestBoxSuggestionChosenEventArgs& args);
|
||||
|
||||
void SettingsNav_Loaded(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
void SettingsNav_ItemInvoked(const Microsoft::UI::Xaml::Controls::NavigationView& sender, const Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs& args);
|
||||
void SaveButton_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& args);
|
||||
@@ -84,21 +92,30 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void _SetupProfileEventHandling(const winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel profile);
|
||||
|
||||
void _PreNavigateHelper();
|
||||
void _Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage);
|
||||
void _Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage);
|
||||
void _Navigate(const Editor::NewTabMenuEntryViewModel& ntmEntryVM, BreadcrumbSubPage subPage);
|
||||
void _Navigate(const Editor::ExtensionPackageViewModel& extPkgVM, BreadcrumbSubPage subPage);
|
||||
void _Navigate(hstring clickedItemTag, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _Navigate(const Editor::ProfileViewModel& profile, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _Navigate(const Editor::ColorSchemeViewModel& colorSchemeVM, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _Navigate(const Editor::NewTabMenuEntryViewModel& ntmEntryVM, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _Navigate(const Editor::ExtensionPackageViewModel& extPkgVM, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _Navigate(const Editor::CommandViewModel& commandVM, BreadcrumbSubPage subPage, hstring elementToFocus = {});
|
||||
void _NavigateToProfileHandler(const IInspectable& sender, winrt::guid profileGuid);
|
||||
void _NavigateToColorSchemeHandler(const IInspectable& sender, const IInspectable& args);
|
||||
Microsoft::UI::Xaml::Controls::NavigationViewItem _FindProfileNavItem(winrt::guid profileGuid) const;
|
||||
|
||||
void _UpdateBackgroundForMica();
|
||||
void _MoveXamlParsedNavItemsIntoItemSource();
|
||||
|
||||
safe_void_coroutine _UpdateSearchIndex();
|
||||
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel _profileDefaultsVM{ nullptr };
|
||||
Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel> _profileVMs{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ActionsViewModel _actionsVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::NewTabMenuViewModel _newTabMenuPageVM{ nullptr };
|
||||
winrt::Microsoft::Terminal::Settings::Editor::ExtensionsViewModel _extensionsVM{ nullptr };
|
||||
|
||||
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable>> _currentSearch{ nullptr };
|
||||
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _profileViewModelChangedRevoker;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _colorSchemesPageViewModelChangedRevoker;
|
||||
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _actionsViewModelChangedRevoker;
|
||||
|
||||
@@ -16,12 +16,11 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
UInt64 GetHostingWindow();
|
||||
}
|
||||
|
||||
// This is used to pass data between pages during navigation.
|
||||
// All pages will migrate to using this in GH #19519.
|
||||
runtimeclass NavigateToPageArgs
|
||||
{
|
||||
IHostedInWindow WindowRoot { get; };
|
||||
IInspectable ViewModel { get; };
|
||||
String ElementToFocus { get; };
|
||||
}
|
||||
|
||||
enum BreadcrumbSubPage
|
||||
|
||||
@@ -52,6 +52,75 @@
|
||||
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<DataTemplate x:Key="BasicSearchResultTemplate"
|
||||
x:DataType="local:FilteredSearchResult">
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
ColumnSpacing="8"
|
||||
ToolTipService.ToolTip="{x:Bind Label}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentPresenter Grid.Column="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="{x:Bind Icon}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{x:Bind Label}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ComplexSearchResultTemplate"
|
||||
x:DataType="local:FilteredSearchResult">
|
||||
<Grid HorizontalAlignment="Stretch"
|
||||
ColumnSpacing="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ContentPresenter Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="{x:Bind Icon}" />
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
FontSize="{ThemeResource BodyTextBlockFontSize}"
|
||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||
Text="{x:Bind Label}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
FontSize="{ThemeResource CaptionTextBlockFontSize}"
|
||||
Foreground="{ThemeResource TextFillColorSecondary}"
|
||||
Text="{x:Bind SecondaryLabel}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<ToolTipService.ToolTip>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="{ThemeResource CaptionTextBlockFontSize}"
|
||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||
Text="{x:Bind Label}" />
|
||||
<TextBlock FontSize="{ThemeResource CaptionTextBlockFontSize}"
|
||||
Foreground="{ThemeResource TextFillColorSecondary}"
|
||||
Text="{x:Bind SecondaryLabel}" />
|
||||
</StackPanel>
|
||||
</ToolTipService.ToolTip>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<local:SearchResultTemplateSelector x:Key="SearchResultTemplateSelector"
|
||||
BasicTemplate="{StaticResource BasicSearchResultTemplate}"
|
||||
ComplexTemplate="{StaticResource ComplexSearchResultTemplate}" />
|
||||
|
||||
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground"
|
||||
Color="Transparent" />
|
||||
<SolidColorBrush x:Key="NavigationViewContentBackground"
|
||||
@@ -99,62 +168,45 @@
|
||||
</Grid>
|
||||
</muxc:NavigationView.Header>
|
||||
|
||||
<muxc:NavigationView.MenuItems>
|
||||
<muxc:NavigationView.AutoSuggestBox>
|
||||
<AutoSuggestBox x:Name="SettingsSearchBox"
|
||||
x:Uid="Nav_SearchBox"
|
||||
ItemTemplateSelector="{StaticResource SearchResultTemplateSelector}"
|
||||
QueryIcon="Find"
|
||||
QuerySubmitted="SettingsSearchBox_QuerySubmitted"
|
||||
SuggestionChosen="SettingsSearchBox_SuggestionChosen"
|
||||
TextChanged="SettingsSearchBox_TextChanged" />
|
||||
</muxc:NavigationView.AutoSuggestBox>
|
||||
|
||||
<muxc:NavigationView.MenuItems>
|
||||
<muxc:NavigationViewItem x:Name="LaunchNavItem"
|
||||
x:Uid="Nav_Launch"
|
||||
Tag="Launch_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="Launch_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="InteractionNavItem"
|
||||
x:Uid="Nav_Interaction"
|
||||
Tag="Interaction_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="Interaction_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="AppearanceNavItem"
|
||||
x:Uid="Nav_Appearance"
|
||||
Tag="GlobalAppearance_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="GlobalAppearance_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="ColorSchemesNavItem"
|
||||
x:Uid="Nav_ColorSchemes"
|
||||
Tag="ColorSchemes_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="ColorSchemes_Nav" />
|
||||
|
||||
|
||||
<muxc:NavigationViewItem x:Name="RenderingNavItem"
|
||||
x:Uid="Nav_Rendering"
|
||||
Tag="Rendering_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="Rendering_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="CompatibilityNavItem"
|
||||
x:Uid="Nav_Compatibility"
|
||||
Tag="Compatibility_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="Compatibility_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="ActionsNavItem"
|
||||
x:Uid="Nav_Actions"
|
||||
Tag="Actions_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge Style="{StaticResource NewInfoBadge}"
|
||||
Visibility="{x:Bind ActionsVM.DisplayBadge, Mode=OneWay}" />
|
||||
@@ -163,42 +215,24 @@
|
||||
|
||||
<muxc:NavigationViewItem x:Name="NewTabMenuNavItem"
|
||||
x:Uid="Nav_NewTabMenu"
|
||||
Tag="NewTabMenu_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="NewTabMenu_Nav" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="ExtensionsNavItem"
|
||||
x:Uid="Nav_Extensions"
|
||||
Tag="Extensions_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="Extensions_Nav" />
|
||||
|
||||
<muxc:NavigationViewItemHeader x:Uid="Nav_Profiles" />
|
||||
|
||||
<muxc:NavigationViewItem x:Name="BaseLayerMenuItem"
|
||||
x:Uid="Nav_ProfileDefaults"
|
||||
Tag="GlobalProfile_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
|
||||
Tag="GlobalProfile_Nav" />
|
||||
</muxc:NavigationView.MenuItems>
|
||||
|
||||
<muxc:NavigationView.FooterMenuItems>
|
||||
<!-- The OpenJson item needs both Tapped and KeyDown handler -->
|
||||
<muxc:NavigationViewItem x:Name="OpenJsonNavItem"
|
||||
x:Uid="Nav_OpenJSON"
|
||||
SelectsOnInvoked="False"
|
||||
Tag="OpenJson_Nav">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<FontIcon Glyph="" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
</muxc:NavigationViewItem>
|
||||
Tag="OpenJson_Nav" />
|
||||
</muxc:NavigationView.FooterMenuItems>
|
||||
|
||||
<Grid>
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
<DependentUpon>NewTabMenu.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="SearchIndex.h" />
|
||||
<ClInclude Include="NavConstants.h" />
|
||||
<ClInclude Include="MainPage.h">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
@@ -173,6 +175,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="Utils.h" />
|
||||
<ClInclude Include="PreviewConnection.h" />
|
||||
<ClInclude Include="$(GeneratedFilesDir)GeneratedSettingsIndex.g.h" />
|
||||
<ClInclude Include="../fzf/fzf.h" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= XAML files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -302,6 +306,7 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SearchIndex.cpp" />
|
||||
<ClCompile Include="MainPage.cpp">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
@@ -384,6 +389,8 @@
|
||||
<ClCompile Include="PreviewConnection.cpp">
|
||||
<DependentUpon>PreviewConnection.h</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)GeneratedSettingsIndex.g.cpp" />
|
||||
<ClCompile Include="../fzf/fzf.cpp" />
|
||||
</ItemGroup>
|
||||
<!-- ========================= idl Files ======================== -->
|
||||
<ItemGroup>
|
||||
@@ -440,6 +447,7 @@
|
||||
<DependentUpon>Rendering.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Midl>
|
||||
<Midl Include="SearchIndex.idl" />
|
||||
<Midl Include="MainPage.idl">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Midl>
|
||||
@@ -556,4 +564,10 @@
|
||||
<!-- This -must- go after cppwinrt.build.post.props because that includes many VS-provided props including appcontainer.common.props, which stomps on what cppwinrt.targets did. -->
|
||||
<Import Project="$(OpenConsoleDir)src\common.nugetversions.targets" />
|
||||
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
|
||||
<Target Name="GenerateSettingsIndex"
|
||||
Inputs="@(Page);$(OpenConsoleDir)tools\GenerateSettingsIndex.ps1"
|
||||
Outputs="$(GeneratedFilesDir)GeneratedSettingsIndex.g.h;$(GeneratedFilesDir)GeneratedSettingsIndex.g.cpp"
|
||||
BeforeTargets="ClCompile">
|
||||
<Exec Command="pwsh.exe -NoProfile -ExecutionPolicy Unrestricted "$(OpenConsoleDir)tools\GenerateSettingsIndex.ps1" -SourceDir "$(MSBuildThisFileDirectory)." -OutputDir "$(MSBuildThisFileDirectory)$(GeneratedFilesDir)."" />
|
||||
</Target>
|
||||
</Project>
|
||||
40
src/cascadia/TerminalSettingsEditor/NavConstants.h
Normal file
40
src/cascadia/TerminalSettingsEditor/NavConstants.h
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <til/static_map.h>
|
||||
|
||||
// Navigation tags used to identify pages in the Settings UI NavigationView.
|
||||
// These tags are stored as the Tag property on NavigationViewItems.
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
inline constexpr std::wstring_view openJsonTag{ L"OpenJson_Nav" };
|
||||
inline constexpr std::wstring_view launchTag{ L"Launch_Nav" };
|
||||
inline constexpr std::wstring_view interactionTag{ L"Interaction_Nav" };
|
||||
inline constexpr std::wstring_view renderingTag{ L"Rendering_Nav" };
|
||||
inline constexpr std::wstring_view compatibilityTag{ L"Compatibility_Nav" };
|
||||
inline constexpr std::wstring_view actionsTag{ L"Actions_Nav" };
|
||||
inline constexpr std::wstring_view newTabMenuTag{ L"NewTabMenu_Nav" };
|
||||
inline constexpr std::wstring_view extensionsTag{ L"Extensions_Nav" };
|
||||
inline constexpr std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" };
|
||||
inline constexpr std::wstring_view addProfileTag{ L"AddProfile" };
|
||||
inline constexpr std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
|
||||
inline constexpr std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" };
|
||||
|
||||
// Map from navigation tags to Segoe MDL2 Assets icon glyphs
|
||||
inline constexpr til::static_map NavTagIconMap{
|
||||
std::pair{ launchTag, L"\xE7B5" }, /* Set Lock Screen */
|
||||
std::pair{ interactionTag, L"\xE7C9" }, /* Touch Pointer */
|
||||
std::pair{ globalAppearanceTag, L"\xE771" }, /* Personalize */
|
||||
std::pair{ colorSchemesTag, L"\xE790" }, /* Color */
|
||||
std::pair{ renderingTag, L"\xE7F8" }, /* Device Laptop No Pic */
|
||||
std::pair{ compatibilityTag, L"\xEC7A" }, /* Developer Tools */
|
||||
std::pair{ actionsTag, L"\xE765" }, /* Keyboard Classic */
|
||||
std::pair{ newTabMenuTag, L"\xE71D" }, /* All Apps */
|
||||
std::pair{ extensionsTag, L"\xEA86" }, /* Puzzle */
|
||||
std::pair{ globalProfileTag, L"\xE81E" }, /* Map Layers */
|
||||
std::pair{ addProfileTag, L"\xE710" }, /* Add */
|
||||
std::pair{ openJsonTag, L"\xE713" }, /* Settings */
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "NewTabMenu.h"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "NewTabMenu.g.cpp"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "NewTabMenuEntryTemplateSelector.g.cpp"
|
||||
@@ -44,6 +45,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::NewTabMenuViewModel>();
|
||||
_weakWindowRoot = args.WindowRoot();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -320,7 +320,8 @@
|
||||
<TextBlock x:Uid="NewTabMenu_CurrentFolderTextBlock"
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
<!-- Name -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_CurrentFolderName"
|
||||
<local:SettingContainer x:Name="CurrentFolderName"
|
||||
x:Uid="NewTabMenu_CurrentFolderName"
|
||||
CurrentValue="{x:Bind ViewModel.CurrentFolderName, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<TextBox Style="{StaticResource TextBoxSettingStyle}"
|
||||
@@ -354,13 +355,15 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Inlining -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_CurrentFolderInlining">
|
||||
<local:SettingContainer x:Name="CurrentFolderInlining"
|
||||
x:Uid="NewTabMenu_CurrentFolderInlining">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderInlining, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Allow Empty -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_CurrentFolderAllowEmpty">
|
||||
<local:SettingContainer x:Name="CurrentFolderAllowEmpty"
|
||||
x:Uid="NewTabMenu_CurrentFolderAllowEmpty">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.CurrentFolderAllowEmpty, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
@@ -372,7 +375,8 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Add Profile -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddProfile"
|
||||
<local:SettingContainer x:Name="AddProfile"
|
||||
x:Uid="NewTabMenu_AddProfile"
|
||||
FontIconGlyph=""
|
||||
Style="{StaticResource SettingContainerWithIcon}">
|
||||
|
||||
@@ -421,7 +425,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Separator -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddSeparator"
|
||||
<local:SettingContainer x:Name="AddSeparator"
|
||||
x:Uid="NewTabMenu_AddSeparator"
|
||||
FontIconGlyph=""
|
||||
Style="{StaticResource SettingContainerWithIcon}">
|
||||
<Button x:Name="AddSeparatorButton"
|
||||
@@ -437,7 +442,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Folder -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddFolder"
|
||||
<local:SettingContainer x:Name="AddFolder"
|
||||
x:Uid="NewTabMenu_AddFolder"
|
||||
FontIconGlyph=""
|
||||
Style="{StaticResource SettingContainerWithIcon}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
@@ -463,7 +469,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Add Match Profiles -->
|
||||
<local:SettingContainer x:Uid="NewTabMenu_AddMatchProfiles"
|
||||
<local:SettingContainer x:Name="AddMatchProfiles"
|
||||
x:Uid="NewTabMenu_AddMatchProfiles"
|
||||
FontIconGlyph=""
|
||||
Style="{StaticResource ExpanderSettingContainerStyleWithIcon}">
|
||||
<StackPanel Spacing="8">
|
||||
|
||||
@@ -510,6 +510,25 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
return _folderTreeCache;
|
||||
}
|
||||
|
||||
Collections::IObservableVector<Editor::FolderEntryViewModel> NewTabMenuViewModel::FolderTreeFlatList() const
|
||||
{
|
||||
std::vector<Editor::FolderEntryViewModel> flatList;
|
||||
_FolderTreeFlatListImpl(_rootEntries, flatList);
|
||||
return single_threaded_observable_vector<Editor::FolderEntryViewModel>(std::move(flatList));
|
||||
}
|
||||
|
||||
void NewTabMenuViewModel::_FolderTreeFlatListImpl(const Windows::Foundation::Collections::IVector<Editor::NewTabMenuEntryViewModel>& entriesToAdd, std::vector<Editor::FolderEntryViewModel>& flatList)
|
||||
{
|
||||
for (const auto& entry : entriesToAdd)
|
||||
{
|
||||
if (const auto& folderVM = entry.try_as<Editor::FolderEntryViewModel>())
|
||||
{
|
||||
flatList.push_back(folderVM);
|
||||
_FolderTreeFlatListImpl(folderVM.Entries(), flatList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This recursively constructs the FolderTree
|
||||
FolderTreeViewEntry::FolderTreeViewEntry(Editor::FolderEntryViewModel folderEntry) :
|
||||
_folderEntry{ folderEntry },
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
Windows::Foundation::Collections::IObservableVector<Model::Profile> AvailableProfiles() const { return _Settings.AllProfiles(); }
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::FolderTreeViewEntry> FolderTree() const;
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::FolderEntryViewModel> FolderTreeFlatList() const;
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::NewTabMenuEntryViewModel> CurrentView() const;
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Editor::FolderEntryViewModel, CurrentFolder, nullptr);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(Editor::FolderTreeViewEntry, CurrentFolderTreeViewSelectedItem, nullptr);
|
||||
@@ -73,6 +74,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
Windows::Foundation::Collections::IObservableVector<Editor::NewTabMenuEntryViewModel>::VectorChanged_revoker _rootEntriesChangedRevoker;
|
||||
|
||||
static bool _IsRemainingProfilesEntryMissing(const Windows::Foundation::Collections::IVector<Editor::NewTabMenuEntryViewModel>& entries);
|
||||
static void _FolderTreeFlatListImpl(const Windows::Foundation::Collections::IVector<Editor::NewTabMenuEntryViewModel>& entriesToAdd, std::vector<Editor::FolderEntryViewModel>& flatList);
|
||||
void _FolderPropertyChanged(const IInspectable& sender, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "DeleteProfileEventArgs.g.h"
|
||||
#include "NavigateToProfileArgs.g.h"
|
||||
#include "BellSoundViewModel.g.h"
|
||||
#include "ProfileViewModel.g.h"
|
||||
#include "Utils.h"
|
||||
@@ -12,21 +11,6 @@
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct NavigateToProfileArgs : NavigateToProfileArgsT<NavigateToProfileArgs>
|
||||
{
|
||||
public:
|
||||
NavigateToProfileArgs(ProfileViewModel profile, Editor::IHostedInWindow windowRoot) :
|
||||
_Profile(profile),
|
||||
_WeakWindowRoot(windowRoot) {}
|
||||
|
||||
Editor::IHostedInWindow WindowRoot() const noexcept { return _WeakWindowRoot ? _WeakWindowRoot.get() : nullptr; }
|
||||
Editor::ProfileViewModel Profile() const noexcept { return _Profile; }
|
||||
|
||||
private:
|
||||
winrt::weak_ref<Editor::IHostedInWindow> _WeakWindowRoot;
|
||||
Editor::ProfileViewModel _Profile{ nullptr };
|
||||
};
|
||||
|
||||
struct BellSoundViewModel : BellSoundViewModelT<BellSoundViewModel>, ViewModelHelper<BellSoundViewModel>
|
||||
{
|
||||
public:
|
||||
@@ -55,6 +39,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
void DeleteProfile();
|
||||
|
||||
void SetupAppearances(Windows::Foundation::Collections::IObservableVector<Editor::ColorSchemeViewModel> schemesList);
|
||||
void ForceRefreshCurrentPage()
|
||||
{
|
||||
// Used to trigger the PropertyChanged handler in MainPage.cpp
|
||||
// This forces the page to refresh
|
||||
_NotifyChanges(L"CurrentPage");
|
||||
}
|
||||
|
||||
// bell style bits
|
||||
hstring BellStylePreview() const;
|
||||
@@ -155,6 +145,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AutoMarkPrompts);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, RepositionCursorWithMouse);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, ForceVTInput);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowKittyKeyboardMode);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowVtChecksumReport);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AllowVtClipboardWrite);
|
||||
OBSERVABLE_PROJECTED_SETTING(_profile, AnswerbackMessage);
|
||||
@@ -163,6 +154,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
WINRT_PROPERTY(bool, IsBaseLayer, false);
|
||||
WINRT_PROPERTY(bool, FocusDeleteButton, false);
|
||||
WINRT_PROPERTY(hstring, ElementToFocus);
|
||||
GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode);
|
||||
GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, CloseOnExit);
|
||||
GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, ScrollState);
|
||||
|
||||
@@ -14,12 +14,6 @@ import "ColorSchemesPageViewModel.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass NavigateToProfileArgs
|
||||
{
|
||||
ProfileViewModel Profile { get; };
|
||||
IHostedInWindow WindowRoot { get; };
|
||||
}
|
||||
|
||||
runtimeclass DeleteProfileEventArgs
|
||||
{
|
||||
Guid ProfileGuid { get; };
|
||||
@@ -140,6 +134,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AutoMarkPrompts);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RepositionCursorWithMouse);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, ForceVTInput);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowKittyKeyboardMode);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowVtChecksumReport);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(String, AnswerbackMessage);
|
||||
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RainbowSuggestions);
|
||||
|
||||
@@ -25,9 +25,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Advanced::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
|
||||
_Profile = args.Profile();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_Profile = args.ViewModel().as<Editor::ProfileViewModel>();
|
||||
_weakWindowRoot = args.WindowRoot();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
<StackPanel Grid.Row="1"
|
||||
Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Antialiasing Mode -->
|
||||
<local:SettingContainer x:Uid="Profile_AntialiasingMode"
|
||||
<local:SettingContainer x:Name="AntialiasingMode"
|
||||
x:Uid="Profile_AntialiasingMode"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAntialiasingMode}"
|
||||
HasSettingValue="{x:Bind Profile.HasAntialiasingMode, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AntialiasingModeOverrideSource, Mode=OneWay}">
|
||||
@@ -49,7 +50,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- AltGr Aliasing -->
|
||||
<local:SettingContainer x:Uid="Profile_AltGrAliasing"
|
||||
<local:SettingContainer x:Name="AltGrAliasing"
|
||||
x:Uid="Profile_AltGrAliasing"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAltGrAliasing}"
|
||||
HasSettingValue="{x:Bind Profile.HasAltGrAliasing, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AltGrAliasingOverrideSource, Mode=OneWay}">
|
||||
@@ -58,7 +60,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Snap On Input -->
|
||||
<local:SettingContainer x:Uid="Profile_SnapOnInput"
|
||||
<local:SettingContainer x:Name="SnapOnInput"
|
||||
x:Uid="Profile_SnapOnInput"
|
||||
ClearSettingValue="{x:Bind Profile.ClearSnapOnInput}"
|
||||
HasSettingValue="{x:Bind Profile.HasSnapOnInput, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.SnapOnInputOverrideSource, Mode=OneWay}">
|
||||
@@ -67,7 +70,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- History Size -->
|
||||
<local:SettingContainer x:Uid="Profile_HistorySize"
|
||||
<local:SettingContainer x:Name="HistorySize"
|
||||
x:Uid="Profile_HistorySize"
|
||||
ClearSettingValue="{x:Bind Profile.ClearHistorySize}"
|
||||
HasSettingValue="{x:Bind Profile.HasHistorySize, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.HistorySizeOverrideSource, Mode=OneWay}">
|
||||
@@ -80,7 +84,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Close On Exit -->
|
||||
<local:SettingContainer x:Uid="Profile_CloseOnExit"
|
||||
<local:SettingContainer x:Name="CloseOnExit"
|
||||
x:Uid="Profile_CloseOnExit"
|
||||
ClearSettingValue="{x:Bind Profile.ClearCloseOnExit}"
|
||||
HasSettingValue="{x:Bind Profile.HasCloseOnExit, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.CloseOnExitOverrideSource, Mode=OneWay}">
|
||||
@@ -92,7 +97,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Bell Style -->
|
||||
<local:SettingContainer x:Uid="Profile_BellStyle"
|
||||
<local:SettingContainer x:Name="BellStyle"
|
||||
x:Uid="Profile_BellStyle"
|
||||
ClearSettingValue="{x:Bind Profile.ClearBellStyle}"
|
||||
CurrentValue="{x:Bind Profile.BellStylePreview, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasBellStyle, Mode=OneWay}"
|
||||
@@ -109,7 +115,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Bell Sound -->
|
||||
<local:SettingContainer x:Uid="Profile_BellSound"
|
||||
<local:SettingContainer x:Name="BellSound"
|
||||
x:Uid="Profile_BellSound"
|
||||
ClearSettingValue="{x:Bind Profile.ClearBellSound}"
|
||||
CurrentValue="{x:Bind Profile.BellSoundPreview, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasBellSound, Mode=OneWay}"
|
||||
@@ -190,7 +197,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- RightClickContextMenu -->
|
||||
<local:SettingContainer x:Uid="Profile_RightClickContextMenu"
|
||||
<local:SettingContainer x:Name="RightClickContextMenu"
|
||||
x:Uid="Profile_RightClickContextMenu"
|
||||
ClearSettingValue="{x:Bind Profile.ClearRightClickContextMenu}"
|
||||
HasSettingValue="{x:Bind Profile.HasRightClickContextMenu, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.RightClickContextMenuOverrideSource, Mode=OneWay}">
|
||||
@@ -199,7 +207,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- ShowMarks -->
|
||||
<local:SettingContainer x:Uid="Profile_ShowMarks"
|
||||
<local:SettingContainer x:Name="ShowMarks"
|
||||
x:Uid="Profile_ShowMarks"
|
||||
ClearSettingValue="{x:Bind Profile.ClearShowMarks}"
|
||||
HasSettingValue="{x:Bind Profile.HasShowMarks, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.ShowMarksOverrideSource, Mode=OneWay}"
|
||||
@@ -209,7 +218,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- AutoMarkPrompts -->
|
||||
<local:SettingContainer x:Uid="Profile_AutoMarkPrompts"
|
||||
<local:SettingContainer x:Name="AutoMarkPrompts"
|
||||
x:Uid="Profile_AutoMarkPrompts"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAutoMarkPrompts}"
|
||||
HasSettingValue="{x:Bind Profile.HasAutoMarkPrompts, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AutoMarkPromptsOverrideSource, Mode=OneWay}"
|
||||
@@ -219,7 +229,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- ReloadEnvVars -->
|
||||
<local:SettingContainer x:Uid="Profile_ReloadEnvVars"
|
||||
<local:SettingContainer x:Name="ReloadEnvVars"
|
||||
x:Uid="Profile_ReloadEnvVars"
|
||||
ClearSettingValue="{x:Bind Profile.ClearReloadEnvironmentVariables}"
|
||||
HasSettingValue="{x:Bind Profile.HasReloadEnvironmentVariables, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.ReloadEnvironmentVariablesOverrideSource, Mode=OneWay}">
|
||||
@@ -228,7 +239,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- RepositionCursorWithMouse -->
|
||||
<local:SettingContainer x:Uid="Profile_RepositionCursorWithMouse"
|
||||
<local:SettingContainer x:Name="RepositionCursorWithMouse"
|
||||
x:Uid="Profile_RepositionCursorWithMouse"
|
||||
ClearSettingValue="{x:Bind Profile.ClearRepositionCursorWithMouse}"
|
||||
HasSettingValue="{x:Bind Profile.HasRepositionCursorWithMouse, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.RepositionCursorWithMouseOverrideSource, Mode=OneWay}"
|
||||
@@ -238,7 +250,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- RainbowSuggestions -->
|
||||
<local:SettingContainer x:Uid="Profile_RainbowSuggestions"
|
||||
<local:SettingContainer x:Name="RainbowSuggestions"
|
||||
x:Uid="Profile_RainbowSuggestions"
|
||||
ClearSettingValue="{x:Bind Profile.ClearRainbowSuggestions}"
|
||||
HasSettingValue="{x:Bind Profile.HasRainbowSuggestions, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.RainbowSuggestionsOverrideSource, Mode=OneWay}">
|
||||
@@ -247,7 +260,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Path Translation -->
|
||||
<local:SettingContainer x:Uid="Profile_PathTranslationStyle"
|
||||
<local:SettingContainer x:Name="PathTranslationStyle"
|
||||
x:Uid="Profile_PathTranslationStyle"
|
||||
ClearSettingValue="{x:Bind Profile.ClearPathTranslationStyle}"
|
||||
HasSettingValue="{x:Bind Profile.HasPathTranslationStyle, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.PathTranslationStyleOverrideSource, Mode=OneWay}">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "Profiles_Appearance.h"
|
||||
#include "Appearances.h"
|
||||
|
||||
#include "ProfileViewModel.h"
|
||||
#include "PreviewConnection.h"
|
||||
@@ -12,6 +13,8 @@
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
|
||||
static constexpr std::wstring_view AppearanceSettingPrefix{ L"App." };
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
Profiles_Appearance::Profiles_Appearance()
|
||||
@@ -22,10 +25,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
|
||||
_Profile = args.Profile();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_Profile = args.ViewModel().as<Editor::ProfileViewModel>();
|
||||
_weakWindowRoot = args.WindowRoot();
|
||||
|
||||
// Settings are stored in Profiles_Appearance and Appearances.
|
||||
// We use the "App." prefix to indicate if it's in Appearances,
|
||||
// and remove it on the way to Appearances object.
|
||||
const auto elementToFocus = args.ElementToFocus();
|
||||
if (elementToFocus.starts_with(AppearanceSettingPrefix))
|
||||
{
|
||||
std::wstring correctedName{ elementToFocus.c_str() };
|
||||
get_self<implementation::Appearances>(DefaultAppearanceView())->BringIntoViewWhenLoaded(hstring{ correctedName.substr(AppearanceSettingPrefix.size()) });
|
||||
}
|
||||
else
|
||||
{
|
||||
BringIntoViewWhenLoaded(elementToFocus);
|
||||
}
|
||||
|
||||
if (!_previewControl)
|
||||
{
|
||||
const auto settings = winrt::get_self<implementation::ProfileViewModel>(_Profile)->TermSettings();
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
|
||||
#include <ThrottledFunc.h>
|
||||
|
||||
#include "Profiles_Appearance.g.h"
|
||||
#include "PreviewConnection.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include "Profiles_Appearance.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct Profiles_Appearance : public HasScrollViewer<Profiles_Appearance>, Profiles_AppearanceT<Profiles_Appearance>
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
CornerRadius="{StaticResource ControlCornerRadius}" />
|
||||
</Border>
|
||||
|
||||
<local:Appearances Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
|
||||
<local:Appearances x:Name="DefaultAppearanceView"
|
||||
Appearance="{x:Bind Profile.DefaultAppearance, Mode=OneWay}"
|
||||
SourceProfile="{x:Bind Profile, Mode=OneWay}"
|
||||
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
|
||||
|
||||
@@ -85,12 +86,12 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Opacity -->
|
||||
<local:SettingContainer x:Name="OpacityContainer"
|
||||
<local:SettingContainer x:Name="Opacity"
|
||||
x:Uid="Profile_Opacity"
|
||||
ClearSettingValue="{x:Bind Profile.ClearOpacity}"
|
||||
HasSettingValue="{x:Bind Profile.HasOpacity, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.OpacityOverrideSource, Mode=OneWay}">
|
||||
<StackPanel x:Name="OpacityControl">
|
||||
<StackPanel>
|
||||
<Grid Style="{StaticResource CustomSliderControlGridStyle}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
@@ -107,12 +108,12 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Use Acrylic -->
|
||||
<local:SettingContainer x:Uid="Profile_UseAcrylic"
|
||||
<local:SettingContainer x:Name="UseAcrylic"
|
||||
x:Uid="Profile_UseAcrylic"
|
||||
ClearSettingValue="{x:Bind Profile.ClearUseAcrylic}"
|
||||
HasSettingValue="{x:Bind Profile.HasUseAcrylic, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.UseAcrylicOverrideSource, Mode=OneWay}">
|
||||
<ToggleSwitch x:Name="UseAcrylicToggleSwitch"
|
||||
IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}"
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.UseAcrylic, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
@@ -124,7 +125,8 @@
|
||||
Style="{StaticResource TextBlockSubHeaderStyle}" />
|
||||
|
||||
<!-- Padding -->
|
||||
<local:SettingContainer x:Uid="Profile_Padding"
|
||||
<local:SettingContainer x:Name="Padding"
|
||||
x:Uid="Profile_Padding"
|
||||
ClearSettingValue="{x:Bind Profile.ClearPadding}"
|
||||
CurrentValue="{x:Bind Profile.Padding, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasPadding, Mode=OneWay}"
|
||||
@@ -191,7 +193,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Scrollbar Visibility -->
|
||||
<local:SettingContainer x:Uid="Profile_ScrollbarVisibility"
|
||||
<local:SettingContainer x:Name="ScrollbarVisibility"
|
||||
x:Uid="Profile_ScrollbarVisibility"
|
||||
ClearSettingValue="{x:Bind Profile.ClearScrollState}"
|
||||
HasSettingValue="{x:Bind Profile.HasScrollState, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.ScrollStateOverrideSource, Mode=OneWay}">
|
||||
@@ -207,7 +210,10 @@
|
||||
Visibility="{x:Bind Profile.EditableUnfocusedAppearance, Mode=OneWay}">
|
||||
<TextBlock x:Uid="Profile_UnfocusedAppearanceTextBlock"
|
||||
Style="{StaticResource TextBlockSubtitleStyle}" />
|
||||
<Button x:Uid="Profile_CreateUnfocusedAppearanceButton"
|
||||
|
||||
<!-- Create Unfocused Appearance -->
|
||||
<Button x:Name="CreateUnfocusedAppearance"
|
||||
x:Uid="Profile_CreateUnfocusedAppearanceButton"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Bottom"
|
||||
Click="CreateUnfocusedAppearance_Click"
|
||||
@@ -224,7 +230,10 @@
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button x:Uid="Profile_DeleteUnfocusedAppearanceButton"
|
||||
|
||||
<!-- Delete Unfocused Appearance -->
|
||||
<Button x:Name="DeleteUnfocusedAppearance"
|
||||
x:Uid="Profile_DeleteUnfocusedAppearanceButton"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Bottom"
|
||||
Click="DeleteUnfocusedAppearance_Click"
|
||||
@@ -241,7 +250,10 @@
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<local:Appearances Appearance="{x:Bind Profile.UnfocusedAppearance, Mode=OneWay}"
|
||||
|
||||
<!-- Unfocused Appearance -->
|
||||
<local:Appearances x:Name="UnfocusedAppearanceView"
|
||||
Appearance="{x:Bind Profile.UnfocusedAppearance, Mode=OneWay}"
|
||||
SourceProfile="{x:Bind Profile, Mode=OneWay}"
|
||||
Visibility="{x:Bind Profile.ShowUnfocusedAppearance, Mode=OneWay}"
|
||||
WindowRoot="{x:Bind WindowRoot, Mode=OneTime}" />
|
||||
|
||||
@@ -29,9 +29,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Base::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
|
||||
_Profile = args.Profile();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_Profile = args.ViewModel().as<Editor::ProfileViewModel>();
|
||||
_weakWindowRoot = args.WindowRoot();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
// Check the use parent directory box if the starting directory is empty
|
||||
if (_Profile.StartingDirectory().empty())
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
Additionally, the JSON stubs generated by auto-generated profiles come with a name,
|
||||
so the name will always be overridden.
|
||||
-->
|
||||
<local:SettingContainer x:Uid="Profile_Name"
|
||||
<local:SettingContainer x:Name="Name"
|
||||
x:Uid="Profile_Name"
|
||||
CurrentValue="{x:Bind Profile.Name, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
@@ -49,7 +50,7 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Commandline -->
|
||||
<local:SettingContainer x:Name="CommandlineContainer"
|
||||
<local:SettingContainer x:Name="Commandline"
|
||||
x:Uid="Profile_Commandline"
|
||||
ClearSettingValue="{x:Bind Profile.ClearCommandline}"
|
||||
CurrentValue="{x:Bind Profile.Commandline, Mode=OneWay}"
|
||||
@@ -70,7 +71,7 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Starting Directory -->
|
||||
<local:SettingContainer x:Name="StartingDirectoryContainer"
|
||||
<local:SettingContainer x:Name="StartingDirectory"
|
||||
x:Uid="Profile_StartingDirectory"
|
||||
ClearSettingValue="{x:Bind Profile.ClearStartingDirectory}"
|
||||
CurrentValue="{x:Bind Profile.CurrentStartingDirectoryPreview, Mode=OneWay}"
|
||||
@@ -99,7 +100,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Icon -->
|
||||
<local:SettingContainer x:Uid="Profile_Icon"
|
||||
<local:SettingContainer x:Name="Icon"
|
||||
x:Uid="Profile_Icon"
|
||||
ClearSettingValue="{x:Bind Profile.ClearIcon}"
|
||||
CurrentValueAccessibleName="{x:Bind Profile.LocalizedIcon, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasIcon, Mode=OneWay}"
|
||||
@@ -128,7 +130,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Tab Title -->
|
||||
<local:SettingContainer x:Uid="Profile_TabTitle"
|
||||
<local:SettingContainer x:Name="TabTitle"
|
||||
x:Uid="Profile_TabTitle"
|
||||
ClearSettingValue="{x:Bind Profile.ClearTabTitle}"
|
||||
CurrentValue="{x:Bind Profile.TabTitlePreview, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasTabTitle, Mode=OneWay}"
|
||||
@@ -155,7 +158,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Elevate -->
|
||||
<local:SettingContainer x:Uid="Profile_Elevate"
|
||||
<local:SettingContainer x:Name="Elevate"
|
||||
x:Uid="Profile_Elevate"
|
||||
ClearSettingValue="{x:Bind Profile.ClearElevate}"
|
||||
HasSettingValue="{x:Bind Profile.HasElevate, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.ElevateOverrideSource, Mode=OneWay}">
|
||||
@@ -164,7 +168,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Hidden -->
|
||||
<local:SettingContainer x:Uid="Profile_Hidden"
|
||||
<local:SettingContainer x:Name="Hidden"
|
||||
x:Uid="Profile_Hidden"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.IsBaseLayer), Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.Hidden, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Base_Orphaned::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
|
||||
_Profile = args.Profile();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_Profile = args.ViewModel().as<Editor::ProfileViewModel>();
|
||||
|
||||
_layoutUpdatedRevoker = LayoutUpdated(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
// This event fires every time the layout changes, but it is always the last one to fire
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<!-- Delete Button -->
|
||||
<local:SettingContainer x:Uid="Profile_Delete_Orphaned">
|
||||
<local:SettingContainer x:Name="DeleteOrphaned"
|
||||
x:Uid="Profile_Delete_Orphaned">
|
||||
<local:SettingContainer.Content>
|
||||
<Button x:Name="DeleteButton"
|
||||
Click="DeleteConfirmation_Click"
|
||||
@@ -40,7 +41,8 @@
|
||||
</local:SettingContainer.Content>
|
||||
</local:SettingContainer>
|
||||
|
||||
<local:SettingContainer x:Uid="Profile_Name">
|
||||
<local:SettingContainer x:Name="Name"
|
||||
x:Uid="Profile_Name">
|
||||
<local:SettingContainer.Content>
|
||||
<TextBlock FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Style="{StaticResource SettingsPageItemDescriptionStyle}"
|
||||
@@ -48,7 +50,8 @@
|
||||
</local:SettingContainer.Content>
|
||||
</local:SettingContainer>
|
||||
|
||||
<local:SettingContainer x:Uid="Profile_Source_Orphaned">
|
||||
<local:SettingContainer x:Name="Source"
|
||||
x:Uid="Profile_Source_Orphaned">
|
||||
<local:SettingContainer.Content>
|
||||
<TextBlock FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||
Style="{StaticResource SettingsPageItemDescriptionStyle}"
|
||||
|
||||
@@ -20,7 +20,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Profiles_Terminal::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_Profile = e.Parameter().as<Editor::ProfileViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_Profile = args.ViewModel().as<Editor::ProfileViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
Style="{StaticResource SettingsStackStyle}">
|
||||
|
||||
<!-- Suppress Application Title -->
|
||||
<local:SettingContainer x:Uid="Profile_SuppressApplicationTitle"
|
||||
<local:SettingContainer x:Name="SuppressApplicationTitle"
|
||||
x:Uid="Profile_SuppressApplicationTitle"
|
||||
ClearSettingValue="{x:Bind Profile.ClearSuppressApplicationTitle}"
|
||||
HasSettingValue="{x:Bind Profile.HasSuppressApplicationTitle, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.SuppressApplicationTitleOverrideSource, Mode=OneWay}">
|
||||
@@ -41,7 +42,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Force VT Input -->
|
||||
<local:SettingContainer x:Uid="Profile_ForceVTInput"
|
||||
<local:SettingContainer x:Name="ForceVTInput"
|
||||
x:Uid="Profile_ForceVTInput"
|
||||
ClearSettingValue="{x:Bind Profile.ClearForceVTInput}"
|
||||
HasSettingValue="{x:Bind Profile.HasForceVTInput, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.ForceVTInputOverrideSource, Mode=OneWay}">
|
||||
@@ -49,8 +51,19 @@
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Kitty Keyboard Mode -->
|
||||
<local:SettingContainer x:Name="AllowKittyKeyboardMode"
|
||||
x:Uid="Profile_AllowKittyKeyboardMode"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAllowKittyKeyboardMode}"
|
||||
HasSettingValue="{x:Bind Profile.HasAllowKittyKeyboardMode, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AllowKittyKeyboardModeOverrideSource, Mode=OneWay}">
|
||||
<ToggleSwitch IsOn="{x:Bind Profile.AllowKittyKeyboardMode, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Allow VT Checksum Report -->
|
||||
<local:SettingContainer x:Uid="Profile_AllowVtChecksumReport"
|
||||
<local:SettingContainer x:Name="AllowVtChecksumReport"
|
||||
x:Uid="Profile_AllowVtChecksumReport"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAllowVtChecksumReport}"
|
||||
HasSettingValue="{x:Bind Profile.HasAllowVtChecksumReport, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AllowVtChecksumReportOverrideSource, Mode=OneWay}">
|
||||
@@ -59,7 +72,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Allow VT Clipboard Writing -->
|
||||
<local:SettingContainer x:Uid="Profile_AllowVtClipboardWrite"
|
||||
<local:SettingContainer x:Name="AllowVtClipboardWrite"
|
||||
x:Uid="Profile_AllowVtClipboardWrite"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAllowVtClipboardWrite}"
|
||||
HasSettingValue="{x:Bind Profile.HasAllowVtClipboardWrite, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.AllowVtClipboardWriteOverrideSource, Mode=OneWay}">
|
||||
@@ -68,7 +82,8 @@
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Answerback Message -->
|
||||
<local:SettingContainer x:Uid="Profile_AnswerbackMessage"
|
||||
<local:SettingContainer x:Name="AnswerbackMessage"
|
||||
x:Uid="Profile_AnswerbackMessage"
|
||||
ClearSettingValue="{x:Bind Profile.ClearAnswerbackMessage}"
|
||||
CurrentValue="{x:Bind Profile.AnswerbackMessagePreview, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasAnswerbackMessage, Mode=OneWay}"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "Rendering.h"
|
||||
#include "NavigateToPageArgs.g.h"
|
||||
#include "Rendering.g.cpp"
|
||||
|
||||
using namespace winrt::Windows::UI::Xaml::Navigation;
|
||||
@@ -16,7 +17,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
void Rendering::OnNavigatedTo(const NavigationEventArgs& e)
|
||||
{
|
||||
_ViewModel = e.Parameter().as<Editor::RenderingViewModel>();
|
||||
const auto args = e.Parameter().as<Editor::NavigateToPageArgs>();
|
||||
_ViewModel = args.ViewModel().as<Editor::RenderingViewModel>();
|
||||
BringIntoViewWhenLoaded(args.ElementToFocus());
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalSettingsEditorProvider,
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
</Page.Resources>
|
||||
|
||||
<StackPanel Style="{StaticResource SettingsStackStyle}">
|
||||
<local:SettingContainer x:Uid="Globals_GraphicsAPI">
|
||||
<local:SettingContainer x:Name="GraphicsAPI"
|
||||
x:Uid="Globals_GraphicsAPI">
|
||||
<ComboBox AutomationProperties.AccessibilityView="Content"
|
||||
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.GraphicsAPIList}"
|
||||
@@ -32,12 +33,14 @@
|
||||
Style="{StaticResource ComboBoxSettingStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<local:SettingContainer x:Uid="Globals_DisablePartialInvalidation">
|
||||
<local:SettingContainer x:Name="DisablePartialInvalidation"
|
||||
x:Uid="Globals_DisablePartialInvalidation">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.DisablePartialInvalidation, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
<local:SettingContainer x:Uid="Globals_SoftwareRendering">
|
||||
<local:SettingContainer x:Name="SoftwareRendering"
|
||||
x:Uid="Globals_SoftwareRendering">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.SoftwareRendering, Mode=TwoWay}"
|
||||
Style="{StaticResource ToggleSwitchInExpanderStyle}" />
|
||||
</local:SettingContainer>
|
||||
|
||||
@@ -546,6 +546,10 @@
|
||||
<value>Use the legacy input encoding</value>
|
||||
<comment>Header for a control to toggle legacy input encoding for the terminal.</comment>
|
||||
</data>
|
||||
<data name="Profile_AllowKittyKeyboardMode.Header" xml:space="preserve">
|
||||
<value>Allow Kitty Keyboard Protocol</value>
|
||||
<comment>{Locked="Kitty"}Kitty is a moniker and its Keyboard Protocol is a protocol specification.</comment>
|
||||
</data>
|
||||
<data name="Profile_AllowVtChecksumReport.Header" xml:space="preserve">
|
||||
<value>Allow DECRQCRA (Request Checksum of Rectangular Area)</value>
|
||||
<comment>{Locked="DECRQCRA"}{Locked="Request Checksum of Rectangular Area"}Header for a control to toggle support for the DECRQCRA control sequence.</comment>
|
||||
@@ -1766,6 +1770,10 @@
|
||||
<value>Keybindings</value>
|
||||
<comment>Name for a control which contains the list of keybindings for the current command.</comment>
|
||||
</data>
|
||||
<data name="Actions_CommandDetails.Text" xml:space="preserve">
|
||||
<value>Command details</value>
|
||||
<comment>Label for the list of editable command details for the current command. This includes the command name and the shortcut action type.</comment>
|
||||
</data>
|
||||
<data name="Actions_Arguments.Text" xml:space="preserve">
|
||||
<value>Additional arguments</value>
|
||||
<comment>Label for the list of editable arguments for the currently selected action.</comment>
|
||||
@@ -2583,19 +2591,19 @@
|
||||
<comment>An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyleWsl.Content" xml:space="preserve">
|
||||
<value>WSL (C:\ -> /mnt/c)</value>
|
||||
<value>WSL (C:\ -> /mnt/c)</value>
|
||||
<comment>{Locked="WSL","C:\","/mnt/c"} An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyleCygwin.Content" xml:space="preserve">
|
||||
<value>Cygwin (C:\ -> /cygdrive/c)</value>
|
||||
<value>Cygwin (C:\ -> /cygdrive/c)</value>
|
||||
<comment>{Locked="Cygwin","C:\","/cygdrive/c"} An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyleMsys2.Content" xml:space="preserve">
|
||||
<value>MSYS2 (C:\ -> /c)</value>
|
||||
<value>MSYS2 (C:\ -> /c)</value>
|
||||
<comment>{Locked="MSYS2","C:\","/c"} An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_PathTranslationStyleMinGW.Content" xml:space="preserve">
|
||||
<value>MinGW (C:\ -> C:/)</value>
|
||||
<value>MinGW (C:\ -> C:/)</value>
|
||||
<comment>{Locked="MinGW","C:\","C:/"} An option to choose from for the "path translation" setting.</comment>
|
||||
</data>
|
||||
<data name="Profile_Delete_Orphaned.Header" xml:space="preserve">
|
||||
@@ -2709,6 +2717,14 @@
|
||||
<data name="Settings_ResetApplicationStateConfirmationButton.Content" xml:space="preserve">
|
||||
<value>Yes, clear the cache</value>
|
||||
</data>
|
||||
<data name="Nav_SearchBox.PlaceholderText" xml:space="preserve">
|
||||
<value>Search for settings</value>
|
||||
<comment>Placeholder text for the main search box in the settings editor.</comment>
|
||||
</data>
|
||||
<data name="Search_NoResults" xml:space="preserve">
|
||||
<value>No results for "{}"</value>
|
||||
<comment>{Locked="{}"} Displayed when no results were found for a given query. "{}" will be replaced with the query.</comment>
|
||||
</data>
|
||||
<data name="IconPicker_BuiltInIcon.PlaceholderText" xml:space="preserve">
|
||||
<value>Type to filter icons</value>
|
||||
<comment>Placeholder text for a text box to filter and select an icon.</comment>
|
||||
|
||||
476
src/cascadia/TerminalSettingsEditor/SearchIndex.cpp
Normal file
476
src/cascadia/TerminalSettingsEditor/SearchIndex.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include "SearchIndex.h"
|
||||
#include "FilteredSearchResult.g.cpp"
|
||||
#include "SearchResultTemplateSelector.g.cpp"
|
||||
#include "NavConstants.h"
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
|
||||
#include <ScopedResourceLoader.h>
|
||||
|
||||
// Weight multipliers for search result scoring.
|
||||
// Higher values prioritize certain types of matches over others.
|
||||
static constexpr int WeightRuntimeObjectMatch = 6; // Direct runtime object name match (e.g., "PowerShell")
|
||||
static constexpr int WeightProfileDefaults = 6; // Profile Defaults setting
|
||||
static constexpr int WeightRuntimeObjectSetting = 5; // Setting with runtime object context (e.g., "PowerShell: Command line")
|
||||
static constexpr int WeightDisplayTextLocalized = 5; // Display text in current locale
|
||||
static constexpr int WeightDisplayTextNeutral = 2; // Display text in English (fallback)
|
||||
|
||||
// Minimum fzf score threshold to filter out low-quality fuzzy matches
|
||||
static constexpr int MinimumMatchScore = 100;
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
namespace MUX = Microsoft::UI::Xaml;
|
||||
namespace WUX = Windows::UI::Xaml;
|
||||
}
|
||||
|
||||
using namespace winrt::Windows::Foundation;
|
||||
using namespace winrt::Windows::Foundation::Collections;
|
||||
using namespace winrt::Windows::System;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
// Retrieves the searchable fields from the LocalizedIndexEntry and their associated weight bonus.
|
||||
// This allows us to prioritize certain fields over others when scoring search results.
|
||||
std::array<std::pair<std::optional<winrt::hstring>, int>, 2> LocalizedIndexEntry::GetSearchableFields() const
|
||||
{
|
||||
// Profile Defaults entries (DisplayTextUid starts with "Profile_") get a higher weight
|
||||
const auto weight = til::starts_with(std::wstring_view{ Entry->DisplayTextUid }, L"Profile_") ? WeightProfileDefaults : WeightDisplayTextLocalized;
|
||||
return { { { std::optional<winrt::hstring>{ Entry->DisplayTextLocalized }, weight },
|
||||
{ DisplayTextNeutral, WeightDisplayTextNeutral } } };
|
||||
}
|
||||
|
||||
const ScopedResourceLoader& EnglishOnlyResourceLoader() noexcept
|
||||
{
|
||||
static ScopedResourceLoader loader{ GetLibraryResourceLoader().WithQualifier(L"language", L"en-US") };
|
||||
return loader;
|
||||
}
|
||||
|
||||
DataTemplate SearchResultTemplateSelector::SelectTemplateCore(const IInspectable& item, const DependencyObject& /*container*/)
|
||||
{
|
||||
return SelectTemplateCore(item);
|
||||
}
|
||||
|
||||
DataTemplate SearchResultTemplateSelector::SelectTemplateCore(const IInspectable& item)
|
||||
{
|
||||
if (const auto searchResultItem = item.try_as<FilteredSearchResult>())
|
||||
{
|
||||
if (!searchResultItem->SecondaryLabel().empty())
|
||||
{
|
||||
return ComplexTemplate();
|
||||
}
|
||||
return BasicTemplate();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Editor::FilteredSearchResult FilteredSearchResult::CreateNoResultsItem(const winrt::hstring& query)
|
||||
{
|
||||
return winrt::make<FilteredSearchResult>(nullptr, nullptr, hstring{ fmt::format(fmt::runtime(std::wstring{ RS_(L"Search_NoResults") }), query) });
|
||||
}
|
||||
|
||||
// Creates a FilteredSearchResult with the given search index entry and runtime object.
|
||||
// The resulting search result will have a label like "<ProfileName>: <display text>" or "<ProfileName>".
|
||||
// This is so that we can reuse the display text from the search index, but also add additional context to which runtime object this search result maps to.
|
||||
Editor::FilteredSearchResult FilteredSearchResult::CreateRuntimeObjectItem(const LocalizedIndexEntry* searchIndexEntry, const Windows::Foundation::IInspectable& runtimeObj)
|
||||
{
|
||||
hstring runtimeObjLabel{};
|
||||
hstring runtimeObjContext{};
|
||||
if (const auto profileVM = runtimeObj.try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
// No runtimeObjContext: profile name and icon should be enough
|
||||
runtimeObjLabel = profileVM.Name();
|
||||
}
|
||||
else if (const auto colorSchemeVM = runtimeObj.try_as<Editor::ColorSchemeViewModel>())
|
||||
{
|
||||
// No runtimeObjContext: scheme name and generic icon should be enough
|
||||
runtimeObjLabel = colorSchemeVM.Name();
|
||||
}
|
||||
else if (const auto ntmFolderEntryVM = runtimeObj.try_as<Editor::FolderEntryViewModel>())
|
||||
{
|
||||
runtimeObjLabel = ntmFolderEntryVM.Name();
|
||||
runtimeObjContext = RS_(L"Nav_NewTabMenu/Content");
|
||||
}
|
||||
else if (const auto extensionPackageVM = runtimeObj.try_as<Editor::ExtensionPackageViewModel>())
|
||||
{
|
||||
runtimeObjLabel = extensionPackageVM.DisplayName();
|
||||
runtimeObjContext = RS_(L"Nav_Extensions/Content");
|
||||
}
|
||||
else if (const auto commandVM = runtimeObj.try_as<Editor::CommandViewModel>())
|
||||
{
|
||||
runtimeObjLabel = commandVM.DisplayName();
|
||||
runtimeObjContext = RS_(L"Nav_Actions/Content");
|
||||
}
|
||||
|
||||
if (const auto& displayText = searchIndexEntry->Entry->DisplayTextLocalized; !displayText.empty())
|
||||
{
|
||||
// Full index entry (for settings within runtime objects)
|
||||
// - primaryText: <displayText>
|
||||
// - secondaryText: <runtimeObjLabel>
|
||||
// navigates to setting container
|
||||
return winrt::make<FilteredSearchResult>(searchIndexEntry, runtimeObj, displayText, runtimeObjLabel);
|
||||
}
|
||||
// Partial index entry (for runtime object main pages)
|
||||
// - primaryText: <runtimeObjLabel>
|
||||
// - secondaryText: <runtimeObjContext>
|
||||
// "PowerShell" --> navigates to main runtime object page (i.e. Profiles_Base)
|
||||
// "SSH" | "Extension" --> navigates to main runtime object page (i.e. Extensions > SSH)
|
||||
return winrt::make<FilteredSearchResult>(searchIndexEntry, runtimeObj, runtimeObjLabel, runtimeObjContext);
|
||||
}
|
||||
|
||||
winrt::hstring FilteredSearchResult::Label() const
|
||||
{
|
||||
if (_overrideLabel)
|
||||
{
|
||||
return *_overrideLabel;
|
||||
}
|
||||
return _SearchIndexEntry->Entry->DisplayTextLocalized;
|
||||
}
|
||||
|
||||
bool FilteredSearchResult::IsNoResultsPlaceholder() const
|
||||
{
|
||||
return _overrideLabel.has_value() && !_NavigationArgOverride;
|
||||
}
|
||||
|
||||
Windows::Foundation::IInspectable FilteredSearchResult::NavigationArg() const
|
||||
{
|
||||
if (_NavigationArgOverride)
|
||||
{
|
||||
return _NavigationArgOverride;
|
||||
}
|
||||
else if (_SearchIndexEntry)
|
||||
{
|
||||
return _SearchIndexEntry->Entry->NavigationArg;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Windows::UI::Xaml::Controls::IconElement FilteredSearchResult::Icon() const
|
||||
{
|
||||
// We need to set the icon size here as opposed to in the XAML.
|
||||
// Setting it in the XAML just crops the icon.
|
||||
static constexpr double iconSize = 16;
|
||||
if (auto navigationArg = NavigationArg())
|
||||
{
|
||||
if (const auto profileVM = navigationArg.try_as<Editor::ProfileViewModel>())
|
||||
{
|
||||
auto icon = UI::IconPathConverter::IconWUX(profileVM.EvaluatedIcon());
|
||||
icon.Width(iconSize);
|
||||
icon.Height(iconSize);
|
||||
return icon;
|
||||
}
|
||||
else if (const auto colorSchemeVM = navigationArg.try_as<Editor::ColorSchemeViewModel>())
|
||||
{
|
||||
WUX::Controls::FontIcon icon{};
|
||||
icon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(iconSize);
|
||||
icon.Glyph(NavTagIconMap[colorSchemesTag]);
|
||||
return icon;
|
||||
}
|
||||
else if (const auto ntmFolderEntryVM = navigationArg.try_as<Editor::FolderEntryViewModel>())
|
||||
{
|
||||
auto icon = UI::IconPathConverter::IconWUX(ntmFolderEntryVM.Icon());
|
||||
icon.Width(iconSize);
|
||||
icon.Height(iconSize);
|
||||
return icon;
|
||||
}
|
||||
else if (const auto extensionPackageVM = navigationArg.try_as<Editor::ExtensionPackageViewModel>())
|
||||
{
|
||||
// TODO GH #19806: IconWUX() sets a size on the icon automatically. This is great
|
||||
// for most icons, but font icons end up being a weird size.
|
||||
// Check if we're using the generic font icon, and, if so, just build it ourselves
|
||||
// so that it looks right.
|
||||
const auto& extPkgVMIconPath = extensionPackageVM.Icon();
|
||||
if (extPkgVMIconPath == NavTagIconMap[extensionsTag])
|
||||
{
|
||||
WUX::Controls::FontIcon icon{};
|
||||
icon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(iconSize);
|
||||
icon.Glyph(NavTagIconMap[extensionsTag]);
|
||||
return icon;
|
||||
}
|
||||
auto icon = UI::IconPathConverter::IconWUX(extPkgVMIconPath);
|
||||
icon.Width(iconSize);
|
||||
icon.Height(iconSize);
|
||||
return icon;
|
||||
}
|
||||
else if (const auto commandVM = navigationArg.try_as<Editor::CommandViewModel>())
|
||||
{
|
||||
WUX::Controls::FontIcon icon{};
|
||||
icon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(iconSize);
|
||||
icon.Glyph(NavTagIconMap[actionsTag]);
|
||||
return icon;
|
||||
}
|
||||
else if (const auto stringNavArg = navigationArg.try_as<hstring>())
|
||||
{
|
||||
WUX::Controls::FontIcon icon{};
|
||||
icon.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
|
||||
icon.FontSize(iconSize);
|
||||
|
||||
if (_SearchIndexEntry->Entry->SubPage == BreadcrumbSubPage::ColorSchemes_Edit)
|
||||
{
|
||||
// If we're editing a color scheme, stringNavArg is the color scheme name.
|
||||
// Use the color scheme icon.
|
||||
icon.Glyph(NavTagIconMap[colorSchemesTag]);
|
||||
return icon;
|
||||
}
|
||||
else if (const auto it = NavTagIconMap.find(*stringNavArg); it != NavTagIconMap.end())
|
||||
{
|
||||
// Use the font icon used by the navigation view item
|
||||
icon.Glyph(it->second);
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Reset the search index to the build-time data from GeneratedSettingsIndex.g.h
|
||||
void SearchIndex::Reset()
|
||||
{
|
||||
// copied from CommandPaletteItems.h
|
||||
static bool shouldIncludeLanguageNeutralResources = [] {
|
||||
try
|
||||
{
|
||||
const auto context{ winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::GetForViewIndependentUse() };
|
||||
const auto qualifiers{ context.QualifierValues() };
|
||||
if (const auto language{ qualifiers.TryLookup(L"language") })
|
||||
{
|
||||
return !til::starts_with_insensitive_ascii(*language, L"en-");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
|
||||
// Creates the LocalizedIndexEntry wrapper objects around the given index entries
|
||||
// and adds them to the given storage vector.
|
||||
auto loadLocalizedIndex = [&](const auto& indexRef) {
|
||||
std::vector<LocalizedIndexEntry> localizedIndex;
|
||||
localizedIndex.reserve(indexRef.size());
|
||||
for (const auto& entry : indexRef)
|
||||
{
|
||||
LocalizedIndexEntry localizedEntry;
|
||||
localizedEntry.Entry = &entry;
|
||||
if (shouldIncludeLanguageNeutralResources)
|
||||
{
|
||||
localizedEntry.DisplayTextNeutral = EnglishOnlyResourceLoader().GetLocalizedString(entry.DisplayTextUid);
|
||||
}
|
||||
localizedIndex.emplace_back(std::move(localizedEntry));
|
||||
}
|
||||
return localizedIndex;
|
||||
};
|
||||
|
||||
IndexData indexData{
|
||||
.mainIndex = loadLocalizedIndex(LoadBuildTimeIndex()),
|
||||
.profileIndex = loadLocalizedIndex(LoadProfileIndex()),
|
||||
.ntmFolderIndex = loadLocalizedIndex(LoadNTMFolderIndex()),
|
||||
.colorSchemeIndex = loadLocalizedIndex(LoadColorSchemeIndex())
|
||||
};
|
||||
|
||||
// Load partial entries for runtime object main pages
|
||||
// (i.e. PowerShell profile --> PartialProfileIndexEntry() --> Profile page w/ PowerShell profile VM as context)
|
||||
indexData.profileIndexEntry.Entry = &PartialProfileIndexEntry();
|
||||
indexData.ntmFolderIndexEntry.Entry = &PartialNTMFolderIndexEntry();
|
||||
indexData.extensionIndexEntry.Entry = &PartialExtensionIndexEntry();
|
||||
indexData.colorSchemeIndexEntry.Entry = &PartialColorSchemeIndexEntry();
|
||||
indexData.actionIndexEntry.Entry = &PartialActionIndexEntry();
|
||||
|
||||
_index = std::move(indexData);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Gets the search results based on the given query string. Can be cancelled.
|
||||
// - Some results (i.e. profiles) are dynamically generated at runtime, so they need to be passed in here so that we can include them.
|
||||
// - LOAD-BEARING: vector views CANNOT be passed by reference. We need the AddRef to avoid lifetime issues with the async operation.
|
||||
// Arguments:
|
||||
// - query - the search query string
|
||||
// - profileVMs - the list of profile view models to search
|
||||
// - ntmFolderVMs - the list of New Tab Menu folder entry view models to search
|
||||
// - colorSchemeVMs - the list of color scheme view models to search
|
||||
// - extensionPkgVMs - the list of extension package view models to search
|
||||
// - commandVMs - the list of command view models to search
|
||||
// Return value:
|
||||
// - The results are sorted by score (best matches first).
|
||||
// - If no results are found, a "no results" placeholder item is returned.
|
||||
IAsyncOperation<IObservableVector<Windows::Foundation::IInspectable>> SearchIndex::SearchAsync(const hstring& query,
|
||||
const IVectorView<Editor::ProfileViewModel> profileVMs,
|
||||
const IVectorView<Editor::FolderEntryViewModel> ntmFolderVMs,
|
||||
const IVectorView<Editor::ColorSchemeViewModel> colorSchemeVMs,
|
||||
const IVectorView<Editor::ExtensionPackageViewModel> extensionPkgVMs,
|
||||
const IVectorView<Editor::CommandViewModel> commandVMs)
|
||||
{
|
||||
co_await winrt::resume_background();
|
||||
|
||||
// The search can be cancelled at any time by the caller.
|
||||
// Get a token to check for cancellation as we go.
|
||||
auto cancellationToken = co_await get_cancellation_token();
|
||||
const auto filter = fzf::matcher::ParsePattern(std::wstring_view{ query });
|
||||
|
||||
std::vector<std::pair<int, Editor::FilteredSearchResult>> scoredResults;
|
||||
for (const auto& entry : _index.mainIndex)
|
||||
{
|
||||
if (cancellationToken())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate best score across all searchable fields for entry
|
||||
int bestScore = 0;
|
||||
for (const auto& [searchTextOpt, weight] : entry.GetSearchableFields())
|
||||
{
|
||||
if (searchTextOpt.has_value())
|
||||
{
|
||||
if (const auto match = fzf::matcher::Match(searchTextOpt.value(), filter))
|
||||
{
|
||||
bestScore = std::max(bestScore, match->Score * weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestScore >= MinimumMatchScore)
|
||||
{
|
||||
scoredResults.emplace_back(bestScore, winrt::make<FilteredSearchResult>(&entry));
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Filter and score index dependent on runtime objects (i.e. profiles)
|
||||
// - Matches against combined text: "<searchable field> <runtime object name>"
|
||||
// - This allows queries like "font size powershell" to find "PowerShell: Font size"
|
||||
// Arguments:
|
||||
// - runtimeObjectList: the list of runtime objects to search (i.e. profiles, ntm folders, extensions, etc...)
|
||||
// - searchIndex: the corresponding localized search index for the runtime object type (i.e. profile -> _index.profileIndex)
|
||||
// - partialSearchIndexEntry: index entry that is populated with the runtime object (i.e. profile -> _index.profileIndexEntry)
|
||||
auto appendRuntimeObjectResults = [&](const auto& runtimeObjectList, const std::vector<LocalizedIndexEntry>& searchIndex, const auto& partialSearchIndexEntry) {
|
||||
for (const auto& runtimeObj : runtimeObjectList)
|
||||
{
|
||||
if (cancellationToken())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for direct runtime object name match first
|
||||
const auto& objName = runtimeObj.Name();
|
||||
const auto objNameMatch = fzf::matcher::Match(objName, filter);
|
||||
if (objNameMatch && objNameMatch->Score >= MinimumMatchScore)
|
||||
{
|
||||
// navigates to runtime object main page (i.e. "PowerShell" Profiles_Base page)
|
||||
scoredResults.emplace_back(objNameMatch->Score * WeightRuntimeObjectMatch,
|
||||
FilteredSearchResult::CreateRuntimeObjectItem(&partialSearchIndexEntry, runtimeObj));
|
||||
}
|
||||
|
||||
for (const auto& entry : searchIndex)
|
||||
{
|
||||
if (cancellationToken())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Calculate best score across all searchable fields for entry
|
||||
int bestScore = 0;
|
||||
for (const auto& [searchTextOpt, _] : entry.GetSearchableFields())
|
||||
{
|
||||
if (searchTextOpt.has_value())
|
||||
{
|
||||
// Score for combined text: "<searchable field> <runtime object name>"
|
||||
const auto combinedText = fmt::format(L"{} {}", std::wstring_view{ searchTextOpt.value() }, std::wstring_view{ objName });
|
||||
const auto combinedMatch = fzf::matcher::Match(combinedText, filter);
|
||||
if (!combinedMatch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto settingMatch = fzf::matcher::Match(searchTextOpt.value(), filter);
|
||||
|
||||
// Scoring:
|
||||
// 1. require EITHER the runtime object OR the setting to match the query independently,
|
||||
// OR the combined match scores very well (handles "font size powershell" where neither matches alone)
|
||||
// 2. only include if query matches combined text (i.e. "font size PowerShell" matches "<setting name> <profile name>")
|
||||
// 3. combined match scores higher than runtime object alone (setting must contribute to the match)
|
||||
// NOTE: don't compare to settingMatch! This allows "font size" to show results for all profiles
|
||||
const auto hasIndependentMatch = objNameMatch || settingMatch;
|
||||
const auto hasStrongCombinedMatch = combinedMatch->Score >= MinimumMatchScore * 3;
|
||||
if (!hasIndependentMatch && !hasStrongCombinedMatch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (combinedMatch->Score > (objNameMatch ? objNameMatch->Score : 0))
|
||||
{
|
||||
bestScore = std::max(combinedMatch->Score,
|
||||
settingMatch ? settingMatch->Score : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestScore >= MinimumMatchScore)
|
||||
{
|
||||
// navigates to runtime object's setting (i.e. "PowerShell: Command line")
|
||||
scoredResults.emplace_back(bestScore * WeightRuntimeObjectSetting,
|
||||
FilteredSearchResult::CreateRuntimeObjectItem(&entry, runtimeObj));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
appendRuntimeObjectResults(profileVMs, _index.profileIndex, _index.profileIndexEntry);
|
||||
appendRuntimeObjectResults(ntmFolderVMs, _index.ntmFolderIndex, _index.ntmFolderIndexEntry);
|
||||
appendRuntimeObjectResults(colorSchemeVMs, _index.colorSchemeIndex, _index.colorSchemeIndexEntry);
|
||||
|
||||
// Simple runtime object matching (no associated search index, just match by display name)
|
||||
auto appendSimpleRuntimeObjectResults = [&](const auto& runtimeObjectList, const LocalizedIndexEntry& indexEntry, auto getDisplayName) {
|
||||
for (const auto& runtimeObj : runtimeObjectList)
|
||||
{
|
||||
if (cancellationToken())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (const auto match = fzf::matcher::Match(getDisplayName(runtimeObj), filter); match && match->Score >= MinimumMatchScore)
|
||||
{
|
||||
// navigates to runtime object page (i.e. "Copy Text" --> Actions > EditAction page)
|
||||
scoredResults.emplace_back(match->Score * WeightRuntimeObjectMatch,
|
||||
FilteredSearchResult::CreateRuntimeObjectItem(&indexEntry, runtimeObj));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
appendSimpleRuntimeObjectResults(extensionPkgVMs, _index.extensionIndexEntry, [](const auto& ext) { return ext.DisplayName(); });
|
||||
appendSimpleRuntimeObjectResults(commandVMs, _index.actionIndexEntry, [](const auto& cmd) { return cmd.DisplayName(); });
|
||||
|
||||
// must be IInspectable to be used as ItemsSource in XAML
|
||||
std::vector<Windows::Foundation::IInspectable> results;
|
||||
if (scoredResults.empty())
|
||||
{
|
||||
// Explicitly show "no results"
|
||||
results.reserve(1);
|
||||
results.emplace_back(FilteredSearchResult::CreateNoResultsItem(query));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sort results by score (descending)
|
||||
results.reserve(scoredResults.size());
|
||||
std::sort(scoredResults.begin(), scoredResults.end(), [](const auto& a, const auto& b) { return a.first > b.first; });
|
||||
std::transform(scoredResults.begin(), scoredResults.end(), std::back_inserter(results), [](const auto& pair) { return pair.second; });
|
||||
}
|
||||
|
||||
if (cancellationToken())
|
||||
{
|
||||
// Search was cancelled; do not return any results
|
||||
co_return single_threaded_observable_vector<Windows::Foundation::IInspectable>();
|
||||
}
|
||||
co_return single_threaded_observable_vector(std::move(results));
|
||||
}
|
||||
}
|
||||
117
src/cascadia/TerminalSettingsEditor/SearchIndex.h
Normal file
117
src/cascadia/TerminalSettingsEditor/SearchIndex.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FilteredSearchResult.g.h"
|
||||
#include "SearchResultTemplateSelector.g.h"
|
||||
#include "GeneratedSettingsIndex.g.h"
|
||||
#include <til/generational.h>
|
||||
#include "..\fzf\fzf.h"
|
||||
|
||||
class ScopedResourceLoader;
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
const ScopedResourceLoader& EnglishOnlyResourceLoader() noexcept;
|
||||
|
||||
// Wrapper for IndexEntry objects.
|
||||
// Adds neutral locale, if necessary.
|
||||
struct LocalizedIndexEntry
|
||||
{
|
||||
std::optional<winrt::hstring> DisplayTextNeutral = std::nullopt;
|
||||
const IndexEntry* Entry = nullptr;
|
||||
|
||||
std::array<std::pair<std::optional<winrt::hstring>, int>, 2> GetSearchableFields() const;
|
||||
};
|
||||
|
||||
// WinRT object representing a single filtered search result
|
||||
struct FilteredSearchResult : FilteredSearchResultT<FilteredSearchResult>
|
||||
{
|
||||
FilteredSearchResult(const LocalizedIndexEntry* entry, const Windows::Foundation::IInspectable& navigationArgOverride = nullptr, const std::optional<hstring>& label = std::nullopt, const hstring secondaryLabel = {}) :
|
||||
_SearchIndexEntry{ entry },
|
||||
_NavigationArgOverride{ navigationArgOverride },
|
||||
_overrideLabel{ label },
|
||||
_secondaryLabel{ secondaryLabel } {}
|
||||
|
||||
static Editor::FilteredSearchResult CreateNoResultsItem(const winrt::hstring& query);
|
||||
static Editor::FilteredSearchResult CreateRuntimeObjectItem(const LocalizedIndexEntry* searchIndexEntry, const Windows::Foundation::IInspectable& runtimeObj);
|
||||
|
||||
hstring ToString() { return Label(); }
|
||||
winrt::hstring Label() const;
|
||||
winrt::hstring SecondaryLabel() const { return _secondaryLabel; };
|
||||
bool IsNoResultsPlaceholder() const;
|
||||
const LocalizedIndexEntry& SearchIndexEntry() const noexcept { return *_SearchIndexEntry; }
|
||||
Windows::Foundation::IInspectable NavigationArg() const;
|
||||
Windows::UI::Xaml::Controls::IconElement Icon() const;
|
||||
|
||||
private:
|
||||
const std::optional<winrt::hstring> _overrideLabel{ std::nullopt };
|
||||
const winrt::hstring _secondaryLabel{};
|
||||
const Windows::Foundation::IInspectable _NavigationArgOverride{ nullptr };
|
||||
const LocalizedIndexEntry* _SearchIndexEntry{ nullptr };
|
||||
};
|
||||
|
||||
struct SearchResultTemplateSelector : SearchResultTemplateSelectorT<SearchResultTemplateSelector>
|
||||
{
|
||||
SearchResultTemplateSelector() = default;
|
||||
|
||||
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const Windows::Foundation::IInspectable& item, const Windows::UI::Xaml::DependencyObject& container);
|
||||
Windows::UI::Xaml::DataTemplate SelectTemplateCore(const Windows::Foundation::IInspectable& item);
|
||||
|
||||
til::property<winrt::Windows::UI::Xaml::DataTemplate> BasicTemplate;
|
||||
til::property<winrt::Windows::UI::Xaml::DataTemplate> ComplexTemplate;
|
||||
};
|
||||
|
||||
// The main search index implemented as a singleton.
|
||||
// The index loads data generated by tools\GenerateSettingsIndex.ps1 (outputs "Generated Files\GeneratedSettingsIndex.g.h" and cpp).
|
||||
// Outputs FilteredSearchResult objects for UI display. UI is determined by SearchResultTemplateSelector.
|
||||
class SearchIndex final
|
||||
{
|
||||
public:
|
||||
static SearchIndex& Instance() noexcept
|
||||
{
|
||||
static SearchIndex instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
SearchIndex(const SearchIndex&) = delete;
|
||||
SearchIndex& operator=(const SearchIndex&) = delete;
|
||||
SearchIndex(SearchIndex&&) = delete;
|
||||
SearchIndex& operator=(SearchIndex&&) = delete;
|
||||
|
||||
void Reset();
|
||||
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IObservableVector<Windows::Foundation::IInspectable>> SearchAsync(const winrt::hstring& query,
|
||||
const Windows::Foundation::Collections::IVectorView<Editor::ProfileViewModel> profileVMs,
|
||||
const Windows::Foundation::Collections::IVectorView<Editor::FolderEntryViewModel> ntmFolderVMs,
|
||||
const Windows::Foundation::Collections::IVectorView<Editor::ColorSchemeViewModel> colorSchemeVMs,
|
||||
const Windows::Foundation::Collections::IVectorView<Editor::ExtensionPackageViewModel> extensionPkgVMs,
|
||||
const Windows::Foundation::Collections::IVectorView<Editor::CommandViewModel> commandVMs);
|
||||
|
||||
private:
|
||||
SearchIndex() = default;
|
||||
struct IndexData
|
||||
{
|
||||
IndexData& operator=(const IndexData& other) = default;
|
||||
|
||||
// Basic index data loaded from GeneratedSettingsIndex.g.h and wrapped as LocalizedIndexEntry objects.
|
||||
// Non-main indices are duplicated at runtime when searching for runtime objects.
|
||||
std::vector<LocalizedIndexEntry> mainIndex;
|
||||
std::vector<LocalizedIndexEntry> profileIndex;
|
||||
std::vector<LocalizedIndexEntry> ntmFolderIndex;
|
||||
std::vector<LocalizedIndexEntry> colorSchemeIndex;
|
||||
|
||||
// Links to main page; used when searching runtime objects
|
||||
LocalizedIndexEntry profileIndexEntry;
|
||||
LocalizedIndexEntry ntmFolderIndexEntry;
|
||||
LocalizedIndexEntry colorSchemeIndexEntry;
|
||||
LocalizedIndexEntry extensionIndexEntry;
|
||||
LocalizedIndexEntry actionIndexEntry;
|
||||
} _index;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
|
||||
{
|
||||
BASIC_FACTORY(SearchResultTemplateSelector);
|
||||
}
|
||||
22
src/cascadia/TerminalSettingsEditor/SearchIndex.idl
Normal file
22
src/cascadia/TerminalSettingsEditor/SearchIndex.idl
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import "MainPage.idl";
|
||||
|
||||
namespace Microsoft.Terminal.Settings.Editor
|
||||
{
|
||||
runtimeclass FilteredSearchResult : Windows.Foundation.IStringable
|
||||
{
|
||||
String Label { get; };
|
||||
String SecondaryLabel { get; };
|
||||
Windows.UI.Xaml.Controls.IconElement Icon { get; };
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass SearchResultTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
|
||||
{
|
||||
SearchResultTemplateSelector();
|
||||
|
||||
Windows.UI.Xaml.DataTemplate BasicTemplate;
|
||||
Windows.UI.Xaml.DataTemplate ComplexTemplate;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SettingContainer.h"
|
||||
|
||||
// This macro must be used alongside GETSET_BINDABLE_ENUM_SETTING.
|
||||
// Use this in your class's constructor after Initialize_Component().
|
||||
// It sorts and initializes the observable list of enum entries with the enum name
|
||||
@@ -116,4 +118,32 @@ struct HasScrollViewer
|
||||
DismissAllPopups(uielem.XamlRoot());
|
||||
}
|
||||
}
|
||||
|
||||
// Finds the element with the given name and brings it into view
|
||||
void BringIntoViewWhenLoaded(const winrt::hstring elementName)
|
||||
{
|
||||
if (elementName.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto* pThis = static_cast<T*>(this);
|
||||
_loadedRevoker = pThis->Loaded(winrt::auto_revoke, [weakThis{ pThis->get_weak() }, elementName](auto&&, auto&&) {
|
||||
if (auto page{ weakThis.get() })
|
||||
{
|
||||
if (const auto& controlToFocus{ page->FindName(elementName).try_as<winrt::Windows::UI::Xaml::Controls::Control>() })
|
||||
{
|
||||
// We need to wait for the page to be loaded
|
||||
// or else the call to StartBringIntoView()
|
||||
// will end up doing nothing
|
||||
controlToFocus.StartBringIntoView();
|
||||
controlToFocus.Focus(winrt::Windows::UI::Xaml::FocusState::Programmatic);
|
||||
}
|
||||
page->_loadedRevoker.revoke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
winrt::Windows::UI::Xaml::FrameworkElement::Loaded_revoker _loadedRevoker;
|
||||
};
|
||||
|
||||
@@ -59,9 +59,8 @@ namespace winrt
|
||||
namespace WARC = ::winrt::Windows::ApplicationModel::Resources::Core;
|
||||
}
|
||||
|
||||
// Like RS_ and RS_fmt, but they use an ambient boolean named "localized" to
|
||||
// determine whether to load the English version of a resource or the localized
|
||||
// one.
|
||||
// Like RS_ and RS_fmt, but they use an ambient context to determine
|
||||
// whether to load the English version of a resource or the localized one.
|
||||
#define RS_switchable_(x) RS_switchable_impl(context, USES_RESOURCE(x))
|
||||
#define RS_switchable_fmt(x, ...) RS_switchable_fmt_impl(context, USES_RESOURCE(x), __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ Author(s):
|
||||
X(bool, ReloadEnvironmentVariables, "compatibility.reloadEnvironmentVariables", true) \
|
||||
X(bool, RainbowSuggestions, "experimental.rainbowSuggestions", false) \
|
||||
X(bool, ForceVTInput, "compatibility.input.forceVT", false) \
|
||||
X(bool, AllowKittyKeyboardMode, "compatibility.kittyKeyboardMode", true) \
|
||||
X(bool, AllowVtChecksumReport, "compatibility.allowDECRQCRA", false) \
|
||||
X(bool, AllowVtClipboardWrite, "compatibility.allowOSC52", true) \
|
||||
X(bool, AllowKeypadMode, "compatibility.allowDECNKM", false) \
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, ReloadEnvironmentVariables);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, RainbowSuggestions);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, ForceVTInput);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowKittyKeyboardMode);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowVtChecksumReport);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowKeypadMode);
|
||||
INHERITABLE_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
X(bool, TrimBlockSelection, true) \
|
||||
X(bool, SuppressApplicationTitle) \
|
||||
X(bool, ForceVTInput, false) \
|
||||
X(bool, AllowKittyKeyboardMode, true) \
|
||||
X(winrt::hstring, StartingTitle) \
|
||||
X(bool, DetectURLs, true) \
|
||||
X(bool, AutoMarkPrompts) \
|
||||
|
||||
@@ -244,6 +244,39 @@ private:
|
||||
static winrt::Windows::UI::Xaml::DependencyProperty _##name##Property;
|
||||
#endif
|
||||
|
||||
#ifndef ATTACHED_DEPENDENCY_PROPERTY
|
||||
#define ATTACHED_DEPENDENCY_PROPERTY(type, name) \
|
||||
public: \
|
||||
static winrt::Windows::UI::Xaml::DependencyProperty name##Property() \
|
||||
{ \
|
||||
return _##name##Property; \
|
||||
} \
|
||||
static type Get##name(winrt::Windows::UI::Xaml::DependencyObject const& target) \
|
||||
{ \
|
||||
auto&& temp{ target.GetValue(_##name##Property) }; \
|
||||
if (temp) \
|
||||
{ \
|
||||
return winrt::unbox_value<type>(temp); \
|
||||
} \
|
||||
\
|
||||
if constexpr (std::is_base_of_v<winrt::Windows::Foundation::IInspectable, type>) \
|
||||
{ \
|
||||
return { nullptr }; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
} \
|
||||
static void Set##name(winrt::Windows::UI::Xaml::DependencyObject const& target, const type& value) \
|
||||
{ \
|
||||
target.SetValue(_##name##Property, winrt::box_value(value)); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
static winrt::Windows::UI::Xaml::DependencyProperty _##name##Property;
|
||||
#endif
|
||||
|
||||
// Use this macro for quickly defining the factory_implementation part of a
|
||||
// class. CppWinrt requires these for the compiler, but more often than not,
|
||||
// they require no customization. See
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include "..\TerminalApp\fzf\fzf.h"
|
||||
#include "..\fzf\fzf.h"
|
||||
|
||||
using namespace Microsoft::Console;
|
||||
using namespace WEX::Logging;
|
||||
|
||||
@@ -117,6 +117,14 @@ using namespace Microsoft::Console::Interactivity;
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// TODO GH#19847: Avoid translating win32im sequences to Kitty Keyboard Protocol temporarily.
|
||||
// This is because as of this writing, our implementation is brand new, and Windows Terminal
|
||||
// needs a toggle to disable it. That only works if ConPTY then doesn't do it anyway.
|
||||
if (const auto inputBuffer = ServiceLocator::LocateGlobals().getConsoleInformation().pInputBuffer)
|
||||
{
|
||||
inputBuffer->GetTerminalInput().ForceDisableKittyKeyboardProtocol(true);
|
||||
}
|
||||
|
||||
// The only way we're initialized is if the args said we're in conpty mode.
|
||||
// If the args say so, then at least one of in, out, or signal was specified
|
||||
_state = State::Initialized;
|
||||
|
||||
@@ -19,6 +19,8 @@ Revision History:
|
||||
|
||||
#include <til/bit.h>
|
||||
|
||||
#include <IDataSource.h>
|
||||
|
||||
// Helper for declaring a variable to store a TEST_METHOD_PROPERTY and get it's value from the test metadata
|
||||
#define INIT_TEST_PROPERTY(type, identifier, description) \
|
||||
type identifier; \
|
||||
@@ -45,6 +47,95 @@ Revision History:
|
||||
|
||||
namespace WEX::TestExecution
|
||||
{
|
||||
struct ArrayIndexTaefAdapterRow : Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataRow>
|
||||
{
|
||||
HRESULT RuntimeClassInitialize(const size_t index)
|
||||
{
|
||||
_index = index;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestData(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
wchar_t buf[16];
|
||||
swprintf_s(buf, L"%zu", _index);
|
||||
|
||||
LONG idx = 0;
|
||||
const auto array = SafeArrayCreateVector(VT_BSTR, 0, 1);
|
||||
SafeArrayPutElement(array, &idx, SysAllocString(buf));
|
||||
*ppData = array;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadataNames(SAFEARRAY** ppMetadataNames) override
|
||||
{
|
||||
*ppMetadataNames = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadata(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
*ppData = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetName(BSTR* ppszRowName) override
|
||||
{
|
||||
*ppszRowName = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index = 0;
|
||||
};
|
||||
|
||||
struct ArrayIndexTaefAdapterSource : Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataSource>
|
||||
{
|
||||
HRESULT RuntimeClassInitialize(const size_t count)
|
||||
{
|
||||
_count = count;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Advance(IDataRow** ppDataRow) override
|
||||
{
|
||||
if (_index < _count)
|
||||
{
|
||||
return Microsoft::WRL::MakeAndInitialize<ArrayIndexTaefAdapterRow>(ppDataRow, _index++);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppDataRow = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset() override
|
||||
{
|
||||
_index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataNames(SAFEARRAY** names) override
|
||||
{
|
||||
LONG idx = 0;
|
||||
const auto array = SafeArrayCreateVector(VT_BSTR, 0, 1);
|
||||
SafeArrayPutElement(array, &idx, SysAllocString(L"index"));
|
||||
*names = array;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataType(BSTR /*name*/, BSTR* type) override
|
||||
{
|
||||
*type = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _count = 0;
|
||||
size_t _index = 0;
|
||||
};
|
||||
|
||||
// Compare two floats using a ULP (unit last place) tolerance of up to 4.
|
||||
// Allows you to compare two floats that are almost equal.
|
||||
// Think of: 0.200000000000000 vs. 0.200000000000001.
|
||||
|
||||
@@ -109,93 +109,6 @@ static constexpr til::point point_offset_by_line(const til::point start, const t
|
||||
// IMPORTANT: reference this _after_ defining point_offset_by_XXX. We need it for some definitions
|
||||
#include "GeneratedUiaTextRangeMovementTests.g.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
#pragma region TAEF hookup for the test case array above
|
||||
struct ArrayIndexTaefAdapterRow : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataRow>
|
||||
{
|
||||
HRESULT RuntimeClassInitialize(const size_t index)
|
||||
{
|
||||
_index = index;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestData(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
const auto indexString{ wil::str_printf<std::wstring>(L"%zu", _index) };
|
||||
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
|
||||
LONG index{ 0 };
|
||||
auto indexBstr{ wil::make_bstr(indexString.c_str()) };
|
||||
(void)SafeArrayPutElement(safeArray, &index, indexBstr.release());
|
||||
*ppData = safeArray;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadataNames(SAFEARRAY** ppMetadataNames) override
|
||||
{
|
||||
*ppMetadataNames = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetMetadata(BSTR /*pszName*/, SAFEARRAY** ppData) override
|
||||
{
|
||||
*ppData = nullptr;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetName(BSTR* ppszRowName) override
|
||||
{
|
||||
*ppszRowName = wil::make_bstr(s_movementTests[_index].name.data()).release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index;
|
||||
};
|
||||
|
||||
struct ArrayIndexTaefAdapterSource : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom | Microsoft::WRL::InhibitFtmBase>, IDataSource>
|
||||
{
|
||||
STDMETHODIMP Advance(IDataRow** ppDataRow) override
|
||||
{
|
||||
if (_index < s_movementTests.size())
|
||||
{
|
||||
Microsoft::WRL::MakeAndInitialize<ArrayIndexTaefAdapterRow>(ppDataRow, _index++);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppDataRow = nullptr;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset() override
|
||||
{
|
||||
_index = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataNames(SAFEARRAY** names) override
|
||||
{
|
||||
auto safeArray{ SafeArrayCreateVector(VT_BSTR, 0, 1) };
|
||||
LONG index{ 0 };
|
||||
auto dataNameBstr{ wil::make_bstr(L"index") };
|
||||
(void)SafeArrayPutElement(safeArray, &index, dataNameBstr.release());
|
||||
*names = safeArray;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetTestDataType(BSTR /*name*/, BSTR* type) override
|
||||
{
|
||||
*type = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _index{ 0 };
|
||||
};
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
extern "C" HRESULT __declspec(dllexport) __cdecl GeneratedMovementTestDataSource(IDataSource** ppDataSource, void*)
|
||||
{
|
||||
auto source{ Microsoft::WRL::Make<ArrayIndexTaefAdapterSource>() };
|
||||
|
||||
@@ -67,6 +67,10 @@ public:
|
||||
virtual void DeleteColumn(const VTInt distance) = 0; // DECDC
|
||||
virtual void SetKeypadMode(const bool applicationMode) = 0; // DECKPAM, DECKPNM
|
||||
virtual void SetAnsiMode(const bool ansiMode) = 0; // DECANM
|
||||
virtual void SetKittyKeyboardProtocol(const VTParameter flags, const VTParameter mode) noexcept = 0; // KKP
|
||||
virtual void QueryKittyKeyboardProtocol() = 0; // KKP
|
||||
virtual void PushKittyKeyboardProtocol(const VTParameter flags) = 0; // KKP
|
||||
virtual void PopKittyKeyboardProtocol(const VTParameter count) = 0; // KKP
|
||||
virtual void SetTopBottomScrollingMargins(const VTInt topMargin, const VTInt bottomMargin) = 0; // DECSTBM
|
||||
virtual void SetLeftRightScrollingMargins(const VTInt leftMargin, const VTInt rightMargin) = 0; // DECSLRM
|
||||
virtual void EnquireAnswerback() = 0; // ENQ
|
||||
|
||||
@@ -2054,6 +2054,51 @@ void AdaptDispatch::SetKeypadMode(const bool fApplicationMode) noexcept
|
||||
_terminalInput.SetInputMode(TerminalInput::Mode::Keypad, fApplicationMode);
|
||||
}
|
||||
|
||||
// - DECANM - Sets the terminal emulation mode to either ANSI-compatible or VT52.
|
||||
// Arguments:
|
||||
// - ansiMode - set to true to enable the ANSI mode, false for VT52 mode.
|
||||
void AdaptDispatch::SetAnsiMode(const bool ansiMode)
|
||||
{
|
||||
// When an attempt is made to update the mode, the designated character sets
|
||||
// need to be reset to defaults, even if the mode doesn't actually change.
|
||||
_termOutput.SoftReset();
|
||||
|
||||
_api.GetStateMachine().SetParserMode(StateMachine::Mode::Ansi, ansiMode);
|
||||
_terminalInput.SetInputMode(TerminalInput::Mode::Ansi, ansiMode);
|
||||
|
||||
// While input mode changes are often forwarded over conpty, we never want
|
||||
// to do that for the DECANM mode.
|
||||
}
|
||||
|
||||
// CSI = flags ; mode u - Sets kitty keyboard protocol flags
|
||||
void AdaptDispatch::SetKittyKeyboardProtocol(const VTParameter flags, const VTParameter mode) noexcept
|
||||
{
|
||||
const auto kittyFlags = gsl::narrow_cast<uint8_t>(flags.value_or(0));
|
||||
const auto KittyKeyboardProtocol = static_cast<TerminalInput::KittyKeyboardProtocolMode>(mode.value_or(1));
|
||||
_terminalInput.SetKittyKeyboardProtocol(kittyFlags, KittyKeyboardProtocol);
|
||||
}
|
||||
|
||||
// CSI ? u - Queries current kitty keyboard protocol flags
|
||||
void AdaptDispatch::QueryKittyKeyboardProtocol()
|
||||
{
|
||||
const auto flags = static_cast<VTInt>(_terminalInput.GetKittyFlags());
|
||||
_ReturnCsiResponse(fmt::format(FMT_COMPILE(L"?{}u"), flags));
|
||||
}
|
||||
|
||||
// CSI > flags u - Pushes current kitty keyboard flags onto the stack and sets new flags
|
||||
void AdaptDispatch::PushKittyKeyboardProtocol(const VTParameter flags)
|
||||
{
|
||||
const auto kittyFlags = gsl::narrow_cast<uint8_t>(flags.value_or(0));
|
||||
_terminalInput.PushKittyFlags(kittyFlags);
|
||||
}
|
||||
|
||||
// CSI < count u - Pops one or more entries from the kitty keyboard stack
|
||||
void AdaptDispatch::PopKittyKeyboardProtocol(const VTParameter count)
|
||||
{
|
||||
const auto popCount = static_cast<size_t>(count.value_or(1));
|
||||
_terminalInput.PopKittyFlags(popCount);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Internal logic for adding or removing lines in the active screen buffer.
|
||||
// This also moves the cursor to the left margin, which is expected behavior for IL and DL.
|
||||
@@ -2148,22 +2193,6 @@ void AdaptDispatch::DeleteColumn(const VTInt distance)
|
||||
_InsertDeleteColumnHelper(-distance);
|
||||
}
|
||||
|
||||
// - DECANM - Sets the terminal emulation mode to either ANSI-compatible or VT52.
|
||||
// Arguments:
|
||||
// - ansiMode - set to true to enable the ANSI mode, false for VT52 mode.
|
||||
void AdaptDispatch::SetAnsiMode(const bool ansiMode)
|
||||
{
|
||||
// When an attempt is made to update the mode, the designated character sets
|
||||
// need to be reset to defaults, even if the mode doesn't actually change.
|
||||
_termOutput.SoftReset();
|
||||
|
||||
_api.GetStateMachine().SetParserMode(StateMachine::Mode::Ansi, ansiMode);
|
||||
_terminalInput.SetInputMode(TerminalInput::Mode::Ansi, ansiMode);
|
||||
|
||||
// While input mode changes are often forwarded over conpty, we never want
|
||||
// to do that for the DECANM mode.
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - DECSTBM - Set Scrolling Region
|
||||
// This control function sets the top and bottom margins for the current page.
|
||||
|
||||
@@ -97,6 +97,10 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void RequestMode(const DispatchTypes::ModeParams param) override; // DECRQM
|
||||
void SetKeypadMode(const bool applicationMode) noexcept override; // DECKPAM, DECKPNM
|
||||
void SetAnsiMode(const bool ansiMode) override; // DECANM
|
||||
void SetKittyKeyboardProtocol(const VTParameter flags, const VTParameter mode) noexcept override; // KKP
|
||||
void QueryKittyKeyboardProtocol() override; // KKP
|
||||
void PushKittyKeyboardProtocol(const VTParameter flags) override; // KKP
|
||||
void PopKittyKeyboardProtocol(const VTParameter count) override; // KKP
|
||||
void SetTopBottomScrollingMargins(const VTInt topMargin,
|
||||
const VTInt bottomMargin) override; // DECSTBM
|
||||
void SetLeftRightScrollingMargins(const VTInt leftMargin,
|
||||
|
||||
@@ -54,6 +54,10 @@ public:
|
||||
void DeleteColumn(const VTInt /*distance*/) override {} // DECDC
|
||||
void SetKeypadMode(const bool /*applicationMode*/) override {} // DECKPAM, DECKPNM
|
||||
void SetAnsiMode(const bool /*ansiMode*/) override {} // DECANM
|
||||
void SetKittyKeyboardProtocol(const VTParameter /*flags*/, const VTParameter /*mode*/) noexcept override {} // KKP
|
||||
void QueryKittyKeyboardProtocol() override {} // KKP
|
||||
void PushKittyKeyboardProtocol(const VTParameter /*flags*/) override {} // KKP
|
||||
void PopKittyKeyboardProtocol(const VTParameter /*count*/) override {} // KKP
|
||||
void SetTopBottomScrollingMargins(const VTInt /*topMargin*/, const VTInt /*bottomMargin*/) override {} // DECSTBM
|
||||
void SetLeftRightScrollingMargins(const VTInt /*leftMargin*/, const VTInt /*rightMargin*/) override {} // DECSLRM
|
||||
void EnquireAnswerback() override {} // ENQ
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="adapterTest.cpp" />
|
||||
<ClCompile Include="inputTest.cpp" />
|
||||
<ClCompile Include="kittyKeyboardProtocol.cpp" />
|
||||
<ClCompile Include="MouseInputTest.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
@@ -71,4 +72,4 @@
|
||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||
<Import Project="$(SolutionDir)src\common.build.tests.props" />
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -27,10 +27,18 @@
|
||||
<ClCompile Include="MouseInputTest.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="kittyKeyboardProtocol.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\precomp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natstepfilter" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
301
src/terminal/adapter/ut_adapter/kittyKeyboardProtocol.cpp
Normal file
301
src/terminal/adapter/ut_adapter/kittyKeyboardProtocol.cpp
Normal file
@@ -0,0 +1,301 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <consoletaeftemplates.hpp>
|
||||
#include <WexTestClass.h>
|
||||
|
||||
#include "../../input/terminalInput.hpp"
|
||||
|
||||
using namespace WEX::TestExecution;
|
||||
using namespace WEX::Logging;
|
||||
using namespace WEX::Common;
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
// Kitty keyboard protocol enhancement flag abbreviations
|
||||
using KF = TerminalInput::KittyKeyboardProtocolFlags;
|
||||
constexpr auto D = KF::DisambiguateEscapeCodes;
|
||||
constexpr auto E = KF::ReportEventTypes;
|
||||
constexpr auto A = KF::ReportAlternateKeys;
|
||||
constexpr auto K = KF::ReportAllKeysAsEscapeCodes;
|
||||
constexpr auto T = KF::ReportAssociatedText;
|
||||
|
||||
namespace
|
||||
{
|
||||
TerminalInput::OutputType process(TerminalInput& input, bool keyDown, uint16_t vk, uint16_t sc, wchar_t ch, uint32_t state)
|
||||
{
|
||||
INPUT_RECORD record{};
|
||||
record.EventType = KEY_EVENT;
|
||||
record.Event.KeyEvent.bKeyDown = keyDown ? TRUE : FALSE;
|
||||
record.Event.KeyEvent.wRepeatCount = 1;
|
||||
record.Event.KeyEvent.wVirtualKeyCode = vk;
|
||||
record.Event.KeyEvent.wVirtualScanCode = sc;
|
||||
record.Event.KeyEvent.uChar.UnicodeChar = ch;
|
||||
record.Event.KeyEvent.dwControlKeyState = state;
|
||||
return input.HandleKey(record);
|
||||
}
|
||||
|
||||
TerminalInput createInput(uint8_t flags)
|
||||
{
|
||||
TerminalInput input;
|
||||
input.SetKittyKeyboardProtocol(flags, TerminalInput::KittyKeyboardProtocolMode::Replace);
|
||||
return input;
|
||||
}
|
||||
|
||||
// Kitty modifier bits: shift=1, alt=2, ctrl=4, super=8, hyper=16, meta=32, caps_lock=64, num_lock=128
|
||||
// Event types: press=1, repeat=2, release=3
|
||||
|
||||
constexpr auto Alt = LEFT_ALT_PRESSED;
|
||||
constexpr auto Ctrl = LEFT_CTRL_PRESSED;
|
||||
constexpr auto Shift = SHIFT_PRESSED;
|
||||
|
||||
struct TestCase
|
||||
{
|
||||
std::wstring_view name;
|
||||
std::wstring_view expected;
|
||||
uint8_t flags;
|
||||
bool keyDown;
|
||||
uint16_t vk;
|
||||
uint16_t sc;
|
||||
wchar_t ch;
|
||||
uint32_t state;
|
||||
};
|
||||
|
||||
constexpr TestCase testCases[] = {
|
||||
// Core behavior: DisambiguateEscapeCodes (D)
|
||||
{ L"D Esc", L"\x1b[27u", D, true, VK_ESCAPE, 1, 0, 0 },
|
||||
{ L"D Ctrl+a", L"\x1b[97;5u", D, true, 'A', 0x1E, L'\x01', Ctrl },
|
||||
{ L"D Ctrl+Alt+a", L"\x1b[97;7u", D, true, 'A', 0x1E, L'\x01', Ctrl | Alt },
|
||||
{ L"D Shift+Alt+a", L"\x1b[97;4u", D, true, 'A', 0x1E, L'A', Shift | Alt },
|
||||
|
||||
// Modifiers with AllKeys (K): all keys use CSI u
|
||||
{ L"K a", L"\x1b[97u", K, true, 'A', 0x1E, L'a', 0 },
|
||||
{ L"K Shift+a", L"\x1b[97;2u", K, true, 'A', 0x1E, L'A', Shift },
|
||||
{ L"K Alt+a", L"\x1b[97;3u", K, true, 'A', 0x1E, L'a', Alt },
|
||||
{ L"K Ctrl+a", L"\x1b[97;5u", K, true, 'A', 0x1E, L'\x01', Ctrl },
|
||||
{ L"K Shift+Alt+a", L"\x1b[97;4u", K, true, 'A', 0x1E, L'A', Shift | Alt },
|
||||
{ L"K Shift+Ctrl+a", L"\x1b[97;6u", K, true, 'A', 0x1E, L'\x01', Shift | Ctrl },
|
||||
{ L"K Alt+Ctrl+a", L"\x1b[97;7u", K, true, 'A', 0x1E, L'\x01', Alt | Ctrl },
|
||||
{ L"K Shift+Alt+Ctrl+a", L"\x1b[97;8u", K, true, 'A', 0x1E, L'\x01', Shift | Alt | Ctrl },
|
||||
{ L"K CapsLock+a", L"\x1b[97;65u", K, true, 'A', 0x1E, L'A', CAPSLOCK_ON },
|
||||
{ L"K NumLock+a", L"\x1b[97;129u", K, true, 'A', 0x1E, L'a', NUMLOCK_ON },
|
||||
{ L"K CapsLock+NumLock+a", L"\x1b[97;193u", K, true, 'A', 0x1E, L'A', CAPSLOCK_ON | NUMLOCK_ON },
|
||||
{ L"K all mods", L"\x1b[97;200u", K, true, 'A', 0x1E, L'\x01', Shift | Alt | Ctrl | CAPSLOCK_ON | NUMLOCK_ON },
|
||||
|
||||
// Enter/Tab/Backspace: CSI u with K
|
||||
{ L"K Enter", L"\x1b[13u", K, true, VK_RETURN, 0x1C, L'\r', 0 },
|
||||
{ L"K Tab", L"\x1b[9u", K, true, VK_TAB, 0x0F, L'\t', 0 },
|
||||
{ L"K Backspace", L"\x1b[127u", K, true, VK_BACK, 0x0E, L'\b', 0 },
|
||||
{ L"K Shift+Enter", L"\x1b[13;2u", K, true, VK_RETURN, 0x1C, L'\r', Shift },
|
||||
{ L"K Ctrl+Tab", L"\x1b[9;5u", K, true, VK_TAB, 0x0F, L'\t', Ctrl },
|
||||
{ L"K Alt+Backspace", L"\x1b[127;3u", K, true, VK_BACK, 0x0E, L'\b', Alt },
|
||||
{ L"K Shift+Tab", L"\x1b[9;2u", K, true, VK_TAB, 0x0F, 0, Shift },
|
||||
|
||||
// Event types (D|E, E|K): release sends ;1:3
|
||||
{ L"D|E Esc press", L"\x1b[27u", D | E, true, VK_ESCAPE, 1, 0, 0 },
|
||||
{ L"D|E Esc release", L"\x1b[27;1:3u", D | E, false, VK_ESCAPE, 1, 0, 0 },
|
||||
{ L"E|K a press", L"\x1b[97u", E | K, true, 'A', 0x1E, L'a', 0 },
|
||||
{ L"E|K a release", L"\x1b[97;1:3u", E | K, false, 'A', 0x1E, L'a', 0 },
|
||||
{ L"E|K Enter release", L"\x1b[13;1:3u", E | K, false, VK_RETURN, 0x1C, L'\r', 0 },
|
||||
{ L"E|K Tab release", L"\x1b[9;1:3u", E | K, false, VK_TAB, 0x0F, L'\t', 0 },
|
||||
{ L"E|K Backspace release", L"\x1b[127;1:3u", E | K, false, VK_BACK, 0x0E, L'\b', 0 },
|
||||
{ L"D|E Shift+Esc press", L"\x1b[27;2u", D | E, true, VK_ESCAPE, 1, 0, Shift },
|
||||
{ L"D|E Shift+Esc release", L"\x1b[27;2:3u", D | E, false, VK_ESCAPE, 1, 0, Shift },
|
||||
|
||||
// Keypad keys (D disambiguates, getting CSI u with PUA codes)
|
||||
{ L"D Numpad0", L"\x1b[57399u", D, true, VK_NUMPAD0, 0x52, L'0', 0 },
|
||||
{ L"D Numpad5", L"\x1b[57404u", D, true, VK_NUMPAD5, 0x4C, L'5', 0 },
|
||||
{ L"D Numpad9", L"\x1b[57408u", D, true, VK_NUMPAD9, 0x49, L'9', 0 },
|
||||
{ L"D Numpad Decimal", L"\x1b[57409u", D, true, VK_DECIMAL, 0x53, L'.', 0 },
|
||||
{ L"D Numpad Divide", L"\x1b[57410u", D, true, VK_DIVIDE, 0x35, L'/', ENHANCED_KEY },
|
||||
{ L"D Numpad Multiply", L"\x1b[57411u", D, true, VK_MULTIPLY, 0x37, L'*', 0 },
|
||||
{ L"D Numpad Subtract", L"\x1b[57412u", D, true, VK_SUBTRACT, 0x4A, L'-', 0 },
|
||||
{ L"D Numpad Add", L"\x1b[57413u", D, true, VK_ADD, 0x4E, L'+', 0 },
|
||||
{ L"D Shift+Numpad5", L"\x1b[57404;2u", D, true, VK_NUMPAD5, 0x4C, L'5', Shift },
|
||||
|
||||
// Lock keys and modifier keys (K reports them)
|
||||
{ L"K CapsLock key", L"\x1b[57358u", K, true, VK_CAPITAL, 0x3A, 0, 0 },
|
||||
{ L"K NumLock key", L"\x1b[57360u", K, true, VK_NUMLOCK, 0x45, 0, ENHANCED_KEY },
|
||||
{ L"K ScrollLock key", L"\x1b[57359u", K, true, VK_SCROLL, 0x46, 0, 0 },
|
||||
{ L"K Left Shift", L"\x1b[57441;2u", K, true, VK_SHIFT, 0x2A, 0, Shift },
|
||||
{ L"K Right Shift", L"\x1b[57447;2u", K, true, VK_SHIFT, 0x36, 0, Shift },
|
||||
{ L"K Left Ctrl", L"\x1b[57442;5u", K, true, VK_CONTROL, 0x1D, 0, Ctrl },
|
||||
{ L"K Right Ctrl", L"\x1b[57448;5u", K, true, VK_CONTROL, 0x1D, 0, Ctrl | ENHANCED_KEY },
|
||||
{ L"K Left Alt", L"\x1b[57443;3u", K, true, VK_MENU, 0x38, 0, Alt },
|
||||
{ L"K Right Alt", L"\x1b[57449;3u", K, true, VK_MENU, 0x38, 0, RIGHT_ALT_PRESSED | ENHANCED_KEY },
|
||||
{ L"K Left Win", L"\x1b[57444u", K, true, VK_LWIN, 0x5B, 0, ENHANCED_KEY },
|
||||
{ L"K Right Win", L"\x1b[57450u", K, true, VK_RWIN, 0x5C, 0, ENHANCED_KEY },
|
||||
|
||||
// Special keys
|
||||
{ L"K Pause", L"\x1b[57362u", K, true, VK_PAUSE, 0x45, 0, 0 },
|
||||
{ L"K PrintScreen", L"\x1b[57361u", K, true, VK_SNAPSHOT, 0x37, 0, ENHANCED_KEY },
|
||||
{ L"K Menu", L"\x1b[57363u", K, true, VK_APPS, 0x5D, 0, ENHANCED_KEY },
|
||||
|
||||
// Navigation keys: enhanced=keypad keys with PUA codes
|
||||
{ L"K Keypad Home", L"\x1b[57423u", K, true, VK_HOME, 0x47, 0, 0 },
|
||||
{ L"K Keypad End", L"\x1b[57424u", K, true, VK_END, 0x4F, 0, 0 },
|
||||
{ L"K Keypad Insert", L"\x1b[57425u", K, true, VK_INSERT, 0x52, 0, 0 },
|
||||
{ L"K Keypad Delete", L"\x1b[57426u", K, true, VK_DELETE, 0x53, 0, 0 },
|
||||
{ L"K Keypad PageUp", L"\x1b[57421u", K, true, VK_PRIOR, 0x49, 0, 0 },
|
||||
{ L"K Keypad PageDown", L"\x1b[57422u", K, true, VK_NEXT, 0x51, 0, 0 },
|
||||
{ L"K Keypad Up", L"\x1b[57419u", K, true, VK_UP, 0x48, 0, 0 },
|
||||
{ L"K Keypad Down", L"\x1b[57420u", K, true, VK_DOWN, 0x50, 0, 0 },
|
||||
{ L"K Keypad Left", L"\x1b[57417u", K, true, VK_LEFT, 0x4B, 0, 0 },
|
||||
{ L"K Keypad Right", L"\x1b[57418u", K, true, VK_RIGHT, 0x4D, 0, 0 },
|
||||
|
||||
// Media keys
|
||||
{ L"K Media Play/Pause", L"\x1b[57430u", K, true, VK_MEDIA_PLAY_PAUSE, 0, 0, 0 },
|
||||
{ L"K Media Stop", L"\x1b[57432u", K, true, VK_MEDIA_STOP, 0, 0, 0 },
|
||||
{ L"K Media Next", L"\x1b[57435u", K, true, VK_MEDIA_NEXT_TRACK, 0, 0, 0 },
|
||||
{ L"K Media Prev", L"\x1b[57436u", K, true, VK_MEDIA_PREV_TRACK, 0, 0, 0 },
|
||||
{ L"K Volume Down", L"\x1b[57438u", K, true, VK_VOLUME_DOWN, 0, 0, 0 },
|
||||
{ L"K Volume Up", L"\x1b[57439u", K, true, VK_VOLUME_UP, 0, 0, 0 },
|
||||
{ L"K Volume Mute", L"\x1b[57440u", K, true, VK_VOLUME_MUTE, 0, 0, 0 },
|
||||
|
||||
// Function keys F13-F24 (PUA codes)
|
||||
{ L"K F13", L"\x1b[57376u", K, true, VK_F13, 0x64, 0, 0 },
|
||||
{ L"K F20", L"\x1b[57383u", K, true, VK_F20, 0x6B, 0, 0 },
|
||||
{ L"K F24", L"\x1b[57387u", K, true, VK_F24, 0x76, 0, 0 },
|
||||
{ L"K Shift+F13", L"\x1b[57376;2u", K, true, VK_F13, 0x64, 0, Shift },
|
||||
|
||||
// Alternate keys (A|K): shifted key and base layout key
|
||||
{ L"A|K Shift+a", L"\x1b[97:65;2u", A | K, true, 'A', 0x1E, L'A', Shift },
|
||||
{ L"A|K Shift+1", L"\x1b[49:33;2u", A | K, true, '1', 0x02, L'!', Shift },
|
||||
{ L"A|K a (no shift)", L"\x1b[97u", A | K, true, 'A', 0x1E, L'a', 0 },
|
||||
|
||||
// Associated text (K|T): text codepoint in 3rd param
|
||||
{ L"K|T Shift+a", L"\x1b[97;2;65u", K | T, true, 'A', 0x1E, L'A', Shift },
|
||||
{ L"K|T Shift+1", L"\x1b[49;2;33u", K | T, true, '1', 0x02, L'!', Shift },
|
||||
{ L"K|T Ctrl+a", L"\x1b[97;5u", K | T, true, 'A', 0x1E, L'\x01', Ctrl }, // control char omitted
|
||||
|
||||
// Edge cases
|
||||
{ L"K Keypad Enter", L"\x1b[57414u", K, true, VK_RETURN, 0x1C, L'\r', ENHANCED_KEY },
|
||||
{ L"K Regular Enter", L"\x1b[13u", K, true, VK_RETURN, 0x1C, L'\r', 0 },
|
||||
{ L"K Shift+Alt+Ctrl+Esc", L"\x1b[27;8u", K, true, VK_ESCAPE, 1, 0, Shift | Alt | Ctrl },
|
||||
{ L"E|K CapsLock+a", L"\x1b[97;65u", E | K, true, 'A', 0x1E, L'A', CAPSLOCK_ON },
|
||||
{ L"E|K all mods release", L"\x1b[97;200:3u", E | K, false, 'A', 0x1E, L'\x01', Shift | Alt | Ctrl | CAPSLOCK_ON | NUMLOCK_ON },
|
||||
|
||||
// F1-F4 with kitty flags (CSI instead of SS3, F3 special case)
|
||||
{ L"D F1", L"\x1b[P", D, true, VK_F1, 0x3B, 0, 0 },
|
||||
{ L"D F2", L"\x1b[Q", D, true, VK_F2, 0x3C, 0, 0 },
|
||||
{ L"D F3", L"\x1b[13~", D, true, VK_F3, 0x3D, 0, 0 }, // F3 uses ~ per updated spec
|
||||
{ L"D F4", L"\x1b[S", D, true, VK_F4, 0x3E, 0, 0 },
|
||||
{ L"D Shift+F1", L"\x1b[1;2P", D, true, VK_F1, 0x3B, 0, Shift },
|
||||
{ L"K F5", L"\x1b[15~", K, true, VK_F5, 0x3F, 0, 0 },
|
||||
{ L"K F12", L"\x1b[24~", K, true, VK_F12, 0x58, 0, 0 },
|
||||
{ L"K Shift+F5", L"\x1b[15;2~", K, true, VK_F5, 0x3F, 0, Shift },
|
||||
|
||||
// Navigation with ENHANCED_KEY (regular arrows, not keypad)
|
||||
{ L"K Up", L"\x1b[A", K, true, VK_UP, 0x48, 0, ENHANCED_KEY },
|
||||
{ L"K Down", L"\x1b[B", K, true, VK_DOWN, 0x50, 0, ENHANCED_KEY },
|
||||
{ L"K Right", L"\x1b[C", K, true, VK_RIGHT, 0x4D, 0, ENHANCED_KEY },
|
||||
{ L"K Left", L"\x1b[D", K, true, VK_LEFT, 0x4B, 0, ENHANCED_KEY },
|
||||
{ L"K Home", L"\x1b[H", K, true, VK_HOME, 0x47, 0, ENHANCED_KEY },
|
||||
{ L"K End", L"\x1b[F", K, true, VK_END, 0x4F, 0, ENHANCED_KEY },
|
||||
{ L"K Insert", L"\x1b[2~", K, true, VK_INSERT, 0x52, 0, ENHANCED_KEY },
|
||||
{ L"K Delete", L"\x1b[3~", K, true, VK_DELETE, 0x53, 0, ENHANCED_KEY },
|
||||
{ L"K PageUp", L"\x1b[5~", K, true, VK_PRIOR, 0x49, 0, ENHANCED_KEY },
|
||||
{ L"K PageDown", L"\x1b[6~", K, true, VK_NEXT, 0x51, 0, ENHANCED_KEY },
|
||||
{ L"K Shift+Up", L"\x1b[1;2A", K, true, VK_UP, 0x48, 0, Shift | ENHANCED_KEY },
|
||||
{ L"K Ctrl+Home", L"\x1b[1;5H", K, true, VK_HOME, 0x47, 0, Ctrl | ENHANCED_KEY },
|
||||
{ L"K Clear", L"\x1b[E", K, true, VK_CLEAR, 0x4C, 0, ENHANCED_KEY },
|
||||
|
||||
// Additional edge cases
|
||||
// F-key with event type
|
||||
{ L"E|K F1 release", L"\x1b[1;1:3P", E | K, false, VK_F1, 0x3B, 0, 0 },
|
||||
{ L"E|K F5 release", L"\x1b[15;1:3~", E | K, false, VK_F5, 0x3F, 0, 0 },
|
||||
// Navigation release
|
||||
{ L"E|K Up release", L"\x1b[1;1:3A", E | K, false, VK_UP, 0x48, 0, ENHANCED_KEY },
|
||||
{ L"E|K Insert release", L"\x1b[2;1:3~", E | K, false, VK_INSERT, 0x52, 0, ENHANCED_KEY },
|
||||
// Alternate keys with modifiers
|
||||
{ L"A|K Shift+Ctrl+a", L"\x1b[97:65;6u", A | K, true, 'A', 0x1E, L'\x01', Shift | Ctrl },
|
||||
// Associated text with plain key
|
||||
{ L"K|T a", L"\x1b[97;;97u", K | T, true, 'A', 0x1E, L'a', 0 },
|
||||
// Text not reported on release
|
||||
{ L"E|K|T a release", L"\x1b[97;1:3u", E | K | T, false, 'A', 0x1E, L'a', 0 },
|
||||
// Escape has no associated text
|
||||
{ L"K|T Esc", L"\x1b[27u", K | T, true, VK_ESCAPE, 1, 0, 0 },
|
||||
// Combined flags: alternate keys with locks
|
||||
{ L"A|K CapsLock+Shift+a", L"\x1b[97:65;66u", A | K, true, 'A', 0x1E, L'a', CAPSLOCK_ON | Shift },
|
||||
// All flags combined
|
||||
{ L"A|K|T Shift+a", L"\x1b[97:65;2;65u", A | K | T, true, 'A', 0x1E, L'A', Shift },
|
||||
|
||||
// Release without EventTypes flag: no output
|
||||
{ L"K a release (no EventTypes)", L"", K, false, 'A', 0x1E, L'a', 0 },
|
||||
|
||||
// Enter/Tab/Backspace release without AllKeys: no output
|
||||
{ L"D|E Enter press", L"\r", D | E, true, VK_RETURN, 0x1C, L'\r', 0 },
|
||||
{ L"D|E Enter release (no AllKeys)", L"", D | E, false, VK_RETURN, 0x1C, L'\r', 0 },
|
||||
|
||||
// Modifier key press/release
|
||||
{ L"E|K Left Shift press", L"\x1b[57441;2u", E | K, true, VK_SHIFT, 0x2A, 0, Shift },
|
||||
{ L"E|K Left Shift release", L"\x1b[57441;1:3u", E | K, false, VK_SHIFT, 0x2A, 0, 0 },
|
||||
|
||||
// Lock key toggle (CapsLock)
|
||||
{ L"E|K CapsLock press", L"\x1b[57358u", E | K, true, VK_CAPITAL, 0x3A, 0, 0 },
|
||||
{ L"E|K CapsLock release (now on)", L"\x1b[57358;65:3u", E | K, false, VK_CAPITAL, 0x3A, 0, CAPSLOCK_ON },
|
||||
|
||||
// Associated text filtering
|
||||
{ L"K|T Shift+a (text)", L"\x1b[97;2;65u", K | T, true, 'A', 0x1E, L'A', Shift },
|
||||
{ L"K|T Ctrl+a (control char filtered)", L"\x1b[97;5u", K | T, true, 'A', 0x1E, L'\x01', Ctrl },
|
||||
{ L"K|T Esc (no text)", L"\x1b[27u", K | T, true, VK_ESCAPE, 1, 0, 0 },
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" HRESULT __declspec(dllexport) __cdecl KittyKeyTestDataSource(IDataSource** ppDataSource, void*)
|
||||
{
|
||||
return Microsoft::WRL::MakeAndInitialize<ArrayIndexTaefAdapterSource>(ppDataSource, std::size(testCases));
|
||||
}
|
||||
|
||||
class KittyKeyboardProtocolTests
|
||||
{
|
||||
TEST_CLASS(KittyKeyboardProtocolTests);
|
||||
|
||||
TEST_METHOD(KeyPressTests)
|
||||
{
|
||||
BEGIN_TEST_METHOD_PROPERTIES()
|
||||
TEST_METHOD_PROPERTY(L"DataSource", L"Export:KittyKeyTestDataSource")
|
||||
END_TEST_METHOD_PROPERTIES()
|
||||
|
||||
DisableVerifyExceptions disableVerifyExceptions{};
|
||||
SetVerifyOutput verifyOutputScope{ VerifyOutputSettings::LogOnlyFailures };
|
||||
|
||||
size_t i{};
|
||||
TestData::TryGetValue(L"index", i);
|
||||
const auto& tc = testCases[i];
|
||||
|
||||
Log::Comment(NoThrowString().Format(L"[%zu] %.*s", i, static_cast<int>(tc.name.size()), tc.name.data()));
|
||||
|
||||
auto input = createInput(tc.flags);
|
||||
const auto expected = TerminalInput::MakeOutput(tc.expected);
|
||||
const auto actual = process(input, tc.keyDown, tc.vk, tc.sc, tc.ch, tc.state);
|
||||
const auto msg = fmt::format(L"{} != {}", til::visualize_control_codes(expected.value_or({})), til::visualize_control_codes(actual.value_or({})));
|
||||
VERIFY_ARE_EQUAL(expected, actual, msg.c_str());
|
||||
}
|
||||
|
||||
TEST_METHOD(KeyRepeatEvents)
|
||||
{
|
||||
auto input = createInput(E | K);
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97u"), process(input, true, 'A', 0x1E, L'a', 0));
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97;1:2u"), process(input, true, 'A', 0x1E, L'a', 0)); // repeat
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97;1:2u"), process(input, true, 'A', 0x1E, L'a', 0)); // repeat
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97;1:3u"), process(input, false, 'A', 0x1E, L'a', 0)); // release
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97u"), process(input, true, 'A', 0x1E, L'a', 0)); // new press
|
||||
}
|
||||
|
||||
TEST_METHOD(KeyRepeatWithModifiers)
|
||||
{
|
||||
auto input = createInput(E | K);
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97;2u"), process(input, true, 'A', 0x1E, L'A', SHIFT_PRESSED));
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97;2:2u"), process(input, true, 'A', 0x1E, L'A', SHIFT_PRESSED));
|
||||
}
|
||||
|
||||
TEST_METHOD(KeyRepeatResetOnDifferentKey)
|
||||
{
|
||||
auto input = createInput(E | K);
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97u"), process(input, true, 'A', 0x1E, L'a', 0));
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[98u"), process(input, true, 'B', 0x30, L'b', 0)); // different key
|
||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"\x1b[97u"), process(input, true, 'A', 0x1E, L'a', 0)); // not repeat
|
||||
}
|
||||
};
|
||||
@@ -26,6 +26,7 @@ SOURCES = \
|
||||
$(SOURCES) \
|
||||
adapterTest.cpp \
|
||||
inputTest.cpp \
|
||||
kittyKeyboardProtocol.cpp \
|
||||
MouseInputTest.cpp \
|
||||
|
||||
INCLUDES = \
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<Import Project="$(SolutionDir)src\common.nugetversions.props" />
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\mouseInput.cpp" />
|
||||
<ClCompile Include="..\mouseInputState.cpp" />
|
||||
<ClCompile Include="..\terminalInput.cpp" />
|
||||
<ClCompile Include="..\precomp.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
|
||||
@@ -487,7 +487,7 @@ TerminalInput::OutputType TerminalInput::_GenerateSGRSequence(const til::point p
|
||||
// True if the alternate buffer is active and alternate scroll mode is enabled and the event is a mouse wheel event.
|
||||
bool TerminalInput::ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept
|
||||
{
|
||||
const auto inAltBuffer{ _mouseInputState.inAlternateBuffer };
|
||||
const auto inAltBuffer{ _inAlternateBuffer };
|
||||
const auto inAltScroll{ _inputMode.test(Mode::AlternateScroll) };
|
||||
const auto wasMouseWheel{ (button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0 };
|
||||
return inAltBuffer && inAltScroll && wasMouseWheel;
|
||||
@@ -499,30 +499,28 @@ bool TerminalInput::ShouldSendAlternateScroll(const unsigned int button, const s
|
||||
// - delta: The scroll wheel delta of the input event
|
||||
TerminalInput::OutputType TerminalInput::_makeAlternateScrollOutput(const unsigned int button, const short delta) const
|
||||
{
|
||||
uint16_t vkey = 0;
|
||||
|
||||
if (button == WM_MOUSEWHEEL)
|
||||
{
|
||||
if (delta > 0)
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_UP));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_DOWN));
|
||||
}
|
||||
vkey = delta > 0 ? VK_UP : VK_DOWN;
|
||||
}
|
||||
else if (button == WM_MOUSEHWHEEL)
|
||||
{
|
||||
if (delta > 0)
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_RIGHT));
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeOutput(_keyMap.at(VK_LEFT));
|
||||
}
|
||||
vkey = delta > 0 ? VK_RIGHT : VK_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const SanitizedKeyEvent key{
|
||||
.virtualKey = vkey,
|
||||
};
|
||||
EncodingHelper enc;
|
||||
_encodeRegular(enc, key);
|
||||
|
||||
std::wstring str;
|
||||
_formatEncodingHelper(enc, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "precomp.h"
|
||||
#include <windows.h>
|
||||
#include "terminalInput.hpp"
|
||||
|
||||
using namespace Microsoft::Console::VirtualTerminal;
|
||||
|
||||
// Routine Description:
|
||||
// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer
|
||||
// Parameters:
|
||||
// <none>
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::UseAlternateScreenBuffer() noexcept
|
||||
{
|
||||
_mouseInputState.inAlternateBuffer = true;
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Notify the MouseInput handler that the screen buffer has been swapped to the alternate buffer
|
||||
// Parameters:
|
||||
// <none>
|
||||
// Return value:
|
||||
// <none>
|
||||
void TerminalInput::UseMainScreenBuffer() noexcept
|
||||
{
|
||||
_mouseInputState.inAlternateBuffer = false;
|
||||
}
|
||||
@@ -30,7 +30,6 @@ PRECOMPILED_INCLUDE = ..\precomp.h
|
||||
SOURCES= \
|
||||
..\terminalInput.cpp \
|
||||
..\mouseInput.cpp \
|
||||
..\mouseInputState.cpp \
|
||||
|
||||
INCLUDES = \
|
||||
$(INCLUDES); \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,26 +47,134 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
AlternateScroll
|
||||
};
|
||||
|
||||
// Kitty keyboard protocol progressive enhancement flags
|
||||
// https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
||||
struct KittyKeyboardProtocolFlags
|
||||
{
|
||||
static constexpr uint8_t None = 0;
|
||||
static constexpr uint8_t DisambiguateEscapeCodes = 1 << 0;
|
||||
static constexpr uint8_t ReportEventTypes = 1 << 1;
|
||||
static constexpr uint8_t ReportAlternateKeys = 1 << 2;
|
||||
static constexpr uint8_t ReportAllKeysAsEscapeCodes = 1 << 3;
|
||||
static constexpr uint8_t ReportAssociatedText = 1 << 4;
|
||||
static constexpr uint8_t All = (1 << 5) - 1;
|
||||
};
|
||||
enum class KittyKeyboardProtocolMode : uint8_t
|
||||
{
|
||||
Replace = 1,
|
||||
Set = 2,
|
||||
Reset = 3,
|
||||
};
|
||||
|
||||
TerminalInput() noexcept;
|
||||
void SetInputMode(const Mode mode, const bool enabled) noexcept;
|
||||
bool GetInputMode(const Mode mode) const noexcept;
|
||||
void UseAlternateScreenBuffer() noexcept;
|
||||
void UseMainScreenBuffer() noexcept;
|
||||
void SetInputMode(Mode mode, bool enabled) noexcept;
|
||||
bool GetInputMode(Mode mode) const noexcept;
|
||||
void ResetInputModes() noexcept;
|
||||
void ForceDisableWin32InputMode(const bool win32InputMode) noexcept;
|
||||
void ForceDisableWin32InputMode(bool win32InputMode) noexcept;
|
||||
void ForceDisableKittyKeyboardProtocol(bool disable) noexcept;
|
||||
|
||||
// Kitty keyboard protocol methods
|
||||
void SetKittyKeyboardProtocol(uint8_t flags, KittyKeyboardProtocolMode mode) noexcept;
|
||||
uint8_t GetKittyFlags() const noexcept;
|
||||
void PushKittyFlags(uint8_t flags);
|
||||
void PopKittyFlags(size_t count);
|
||||
void ResetKittyKeyboardProtocols() noexcept;
|
||||
|
||||
#pragma region MouseInput
|
||||
// These methods are defined in mouseInput.cpp
|
||||
|
||||
bool IsTrackingMouseInput() const noexcept;
|
||||
bool ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MouseInputState Management
|
||||
// These methods are defined in mouseInputState.cpp
|
||||
void UseAlternateScreenBuffer() noexcept;
|
||||
void UseMainScreenBuffer() noexcept;
|
||||
bool ShouldSendAlternateScroll(unsigned int button, short delta) const noexcept;
|
||||
#pragma endregion
|
||||
|
||||
private:
|
||||
struct CodepointBuffer
|
||||
{
|
||||
#pragma warning(suppress : 26495) // Variable '...' is uninitialized. Always initialize a member variable (type.6).
|
||||
explicit CodepointBuffer() noexcept = default;
|
||||
explicit CodepointBuffer(uint32_t cp) noexcept;
|
||||
|
||||
void convertLowercase() noexcept;
|
||||
uint32_t asSingleCodepoint() const noexcept;
|
||||
|
||||
wchar_t buf[4];
|
||||
int len = 0;
|
||||
};
|
||||
|
||||
struct SanitizedKeyEvent
|
||||
{
|
||||
uint16_t virtualKey = 0;
|
||||
uint16_t scanCode = 0;
|
||||
uint32_t codepoint = 0;
|
||||
uint32_t controlKeyState = 0;
|
||||
bool leftCtrlIsReallyPressed = false;
|
||||
bool keyDown = false;
|
||||
bool keyRepeat = false;
|
||||
|
||||
bool anyAltPressed() const noexcept;
|
||||
bool bothAltPressed() const noexcept;
|
||||
bool rightAltPressed() const noexcept;
|
||||
bool bothCtrlPressed() const noexcept;
|
||||
bool altGrPressed() const noexcept;
|
||||
};
|
||||
|
||||
struct KeyboardHelper
|
||||
{
|
||||
#pragma warning(suppress : 26495) // Variable '...' is uninitialized. Always initialize a member variable (type.6).
|
||||
explicit KeyboardHelper() noexcept = default;
|
||||
|
||||
uint32_t getUnmodifiedKeyboardKey(const SanitizedKeyEvent& key) noexcept; // Without Ctrl/Alt
|
||||
uint32_t getKittyBaseKey(const SanitizedKeyEvent& key) noexcept; // Without Ctrl/Alt/Shift
|
||||
uint32_t getKittyShiftedKey(const SanitizedKeyEvent& key) noexcept; // Without Ctrl/Alt, with Shift
|
||||
uint32_t getKittyUSBaseKey(const SanitizedKeyEvent& key) noexcept; // Without Ctrl/Alt/Shift in US layout
|
||||
|
||||
private:
|
||||
uint32_t getKeyboardKey(UINT vkey, DWORD controlKeyState, HKL hkl) noexcept;
|
||||
void init() noexcept;
|
||||
void initSlow() noexcept;
|
||||
|
||||
bool _initialized = false;
|
||||
|
||||
// Intentionally uninitialized until first use.
|
||||
HKL _keyboardLayout;
|
||||
uint8_t _keyboardState[256];
|
||||
};
|
||||
|
||||
struct EncodingHelper
|
||||
{
|
||||
explicit EncodingHelper() noexcept;
|
||||
|
||||
bool shiftPressed() const noexcept;
|
||||
bool altPressed() const noexcept;
|
||||
bool ctrlPressed() const noexcept;
|
||||
|
||||
// The KKP CSI u sequence is a superset of other CSI sequences:
|
||||
// CSI unicode-key-code:alternate-key-code-shift:alternate-key-code-base ; modifiers:event-type ; text-as-codepoint u
|
||||
uint32_t csiUnicodeKeyCode;
|
||||
uint32_t csiAltKeyCodeShifted; // KKP-specific
|
||||
uint32_t csiAltKeyCodeBase; // KKP-specific
|
||||
uint32_t csiModifier; // NOTE: The final VT sequence expects this to be 1-based.
|
||||
uint32_t csiEventType; // KKP-specific
|
||||
uint32_t csiTextAsCodepoint; // KKP-specific
|
||||
// A non-zero csiFinal value indicates that this key
|
||||
// should be encoded as `CSI ... ; $csiFinal`.
|
||||
wchar_t csiFinal;
|
||||
|
||||
// A non-zero ss3Final value indicates that this key
|
||||
// should be encoded as `ESC O $ss3Final`.
|
||||
wchar_t ss3Final;
|
||||
|
||||
// If true, and Alt is pressed, an ESC prefix should be added to
|
||||
// the final sequence. This only applies to non-KKP encodings.
|
||||
bool altPrefix;
|
||||
|
||||
// Any other encoding ends up as a non-zero plain value.
|
||||
// For instance, the Tab key gets translated to a plain "\t".
|
||||
std::wstring_view plain;
|
||||
};
|
||||
|
||||
// storage location for the leading surrogate of a utf-16 surrogate pair
|
||||
wchar_t _leadingSurrogate = 0;
|
||||
|
||||
@@ -74,30 +182,41 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
DWORD _lastControlKeyState = 0;
|
||||
uint64_t _lastLeftCtrlTime = 0;
|
||||
uint64_t _lastRightAltTime = 0;
|
||||
std::unordered_map<int, std::wstring> _keyMap;
|
||||
std::wstring _focusInSequence;
|
||||
std::wstring _focusOutSequence;
|
||||
|
||||
til::enumset<Mode> _inputMode{ Mode::Ansi, Mode::AutoRepeat, Mode::AlternateScroll };
|
||||
bool _forceDisableWin32InputMode{ false };
|
||||
bool _inAlternateBuffer{ false };
|
||||
|
||||
const wchar_t* _csi = L"\x1B[";
|
||||
const wchar_t* _ss3 = L"\x1BO";
|
||||
// Kitty keyboard protocol state
|
||||
static constexpr size_t KittyStackMaxSize = 8;
|
||||
bool _forceDisableKittyKeyboardProtocol = false;
|
||||
uint8_t _kittyFlags = 0;
|
||||
std::vector<uint8_t> _kittyMainStack;
|
||||
std::vector<uint8_t> _kittyAltStack;
|
||||
|
||||
std::wstring_view _csi;
|
||||
std::wstring_view _ss3;
|
||||
std::wstring_view _focusInSequence;
|
||||
std::wstring_view _focusOutSequence;
|
||||
|
||||
void _initKeyboardMap() noexcept;
|
||||
DWORD _trackControlKeyState(const KEY_EVENT_RECORD& key) noexcept;
|
||||
std::array<byte, 256> _getKeyboardState(const WORD virtualKeyCode, const DWORD controlKeyState) const;
|
||||
[[nodiscard]] static wchar_t _makeCtrlChar(const wchar_t ch);
|
||||
[[nodiscard]] StringType _makeCharOutput(wchar_t ch);
|
||||
[[nodiscard]] static uint32_t _makeCtrlChar(uint32_t ch) noexcept;
|
||||
[[nodiscard]] static StringType _makeCharOutput(uint32_t ch);
|
||||
[[nodiscard]] static StringType _makeNoOutput() noexcept;
|
||||
[[nodiscard]] void _escapeOutput(StringType& charSequence, const bool altIsPressed) const;
|
||||
[[nodiscard]] OutputType _makeWin32Output(const KEY_EVENT_RECORD& key) const;
|
||||
[[nodiscard]] OutputType _makeWin32Output(const KEY_EVENT_RECORD& key);
|
||||
bool _encodeKitty(KeyboardHelper& kbd, EncodingHelper& enc, const SanitizedKeyEvent& key) noexcept;
|
||||
static uint32_t _getKittyFunctionalKeyCode(UINT vkey, WORD scanCode, bool enhanced) noexcept;
|
||||
void _encodeRegular(EncodingHelper& enc, const SanitizedKeyEvent& key) const noexcept;
|
||||
bool _formatEncodingHelper(EncodingHelper& enc, std::wstring& str) const;
|
||||
void _formatFallback(KeyboardHelper& kbd, const EncodingHelper& enc, const SanitizedKeyEvent& key, std::wstring& seq) const;
|
||||
static void _stringPushCodepoint(std::wstring& str, uint32_t cp);
|
||||
static uint32_t _codepointToLower(uint32_t cp) noexcept;
|
||||
|
||||
#pragma region MouseInputState Management
|
||||
// These methods are defined in mouseInputState.cpp
|
||||
struct MouseInputState
|
||||
{
|
||||
bool inAlternateBuffer{ false };
|
||||
til::point lastPos{ -1, -1 };
|
||||
unsigned int lastButton{ 0 };
|
||||
int accumulatedDelta{ 0 };
|
||||
@@ -113,7 +232,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
[[nodiscard]] OutputType _makeAlternateScrollOutput(unsigned int button, short delta) const;
|
||||
|
||||
static constexpr unsigned int s_GetPressedButton(const MouseButtonState state) noexcept;
|
||||
static constexpr unsigned int s_GetPressedButton(MouseButtonState state) noexcept;
|
||||
#pragma endregion
|
||||
};
|
||||
}
|
||||
|
||||
@@ -670,6 +670,18 @@ bool OutputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParamete
|
||||
case CsiActionCodes::DECPS_PlaySound:
|
||||
_dispatch->PlaySounds(parameters);
|
||||
break;
|
||||
case CsiActionCodes::KKP_KittyKeyboardSet:
|
||||
_dispatch->SetKittyKeyboardProtocol(parameters.at(0), parameters.at(1));
|
||||
break;
|
||||
case CsiActionCodes::KKP_KittyKeyboardQuery:
|
||||
_dispatch->QueryKittyKeyboardProtocol();
|
||||
break;
|
||||
case CsiActionCodes::KKP_KittyKeyboardPush:
|
||||
_dispatch->PushKittyKeyboardProtocol(parameters.at(0));
|
||||
break;
|
||||
case CsiActionCodes::KKP_KittyKeyboardPop:
|
||||
_dispatch->PopKittyKeyboardProtocol(parameters.at(0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,11 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
DECRQCRA_RequestChecksumRectangularArea = VTID("*y"),
|
||||
DECINVM_InvokeMacro = VTID("*z"),
|
||||
DECAC_AssignColor = VTID(",|"),
|
||||
DECPS_PlaySound = VTID(",~")
|
||||
DECPS_PlaySound = VTID(",~"),
|
||||
KKP_KittyKeyboardSet = VTID("=u"),
|
||||
KKP_KittyKeyboardQuery = VTID("?u"),
|
||||
KKP_KittyKeyboardPush = VTID(">u"),
|
||||
KKP_KittyKeyboardPop = VTID("<u")
|
||||
};
|
||||
|
||||
enum DcsActionCodes : uint64_t
|
||||
|
||||
558
tools/GenerateSettingsIndex.ps1
Normal file
558
tools/GenerateSettingsIndex.ps1
Normal file
@@ -0,0 +1,558 @@
|
||||
<#
|
||||
Copyright (c) Microsoft Corporation.
|
||||
Licensed under the MIT license.
|
||||
.SYNOPSIS
|
||||
Scans XAML files for local:SettingContainer entries and generates GeneratedSettingsIndex.g.h / .g.cpp.
|
||||
|
||||
.PARAMETER SourceDir
|
||||
Directory to scan recursively for .xaml files.
|
||||
|
||||
.PARAMETER OutputDir
|
||||
Directory to place generated C++ files.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)][string]$SourceDir,
|
||||
[Parameter(Mandatory=$false)][string]$OutputDir
|
||||
)
|
||||
|
||||
# Prohibited UIDs (exact match, case-insensitive by default)
|
||||
$ProhibitedUids = @(
|
||||
'Extensions_Scope',
|
||||
'Profile_MissingFontFaces',
|
||||
'Profile_ProportionalFontFaces',
|
||||
'ColorScheme_InboxSchemeDuplicate',
|
||||
'ColorScheme_ColorsHeader',
|
||||
'ColorScheme_Rename'
|
||||
)
|
||||
|
||||
# Prohibited XAML files
|
||||
$ProhibitedXamlFiles = @(
|
||||
'CommonResources.xaml',
|
||||
'KeyChordListener.xaml',
|
||||
'NullableColorPicker.xaml',
|
||||
'SettingContainerStyle.xaml',
|
||||
'AISettings.xaml',
|
||||
'Profiles_Base_Orphaned.xaml'
|
||||
)
|
||||
|
||||
if (-not (Test-Path $SourceDir)) { throw "SourceDir not found: $SourceDir" }
|
||||
if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir | Out-Null }
|
||||
|
||||
$resourceKeys = ([xml](Get-Content "$($SourceDir)\Resources\en-US\Resources.resw")).root.data.name
|
||||
$entries = @()
|
||||
|
||||
Get-ChildItem -Path $SourceDir -Recurse -Filter *.xaml | ForEach-Object {
|
||||
# Skip whole file if prohibited
|
||||
$filename = $_.Name
|
||||
if ($ProhibitedXamlFiles -contains $filename)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
$text = Get-Content -Raw -LiteralPath $_.FullName
|
||||
|
||||
# Extract Page x:Class
|
||||
$pageClass = $null
|
||||
if ($text -match '<Page\b[^>]*\bx:Class="([^"]+)"')
|
||||
{
|
||||
$pageClass = $matches[1]
|
||||
}
|
||||
elseif ($filename -eq 'Appearances.xaml')
|
||||
{
|
||||
# Appearances.xaml is a UserControl that is hosted in Profiles_Appearance.xaml
|
||||
$pageClass = 'Microsoft::Terminal::Settings::Editor::Profiles_Appearance'
|
||||
}
|
||||
else
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
# Convert XAML namespace dots to C++ scope operators
|
||||
$pageClass = ($pageClass -replace '\.', '::')
|
||||
|
||||
# Deduce BreadcrumbSubPage
|
||||
# Special cases:
|
||||
# - NewTabMenu: defer to UID, see NavigationParam section below
|
||||
# - Extensions: defer to UID, see NavigationParam section below
|
||||
$subPage = 'BreadcrumbSubPage::'
|
||||
if ($pageClass -match 'Editor::Profiles_Appearance')
|
||||
{
|
||||
$subPage += 'Profile_Appearance'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Profiles_Terminal')
|
||||
{
|
||||
$subPage += 'Profile_Terminal'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Profiles_Advanced')
|
||||
{
|
||||
$subPage += 'Profile_Advanced'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::EditColorScheme')
|
||||
{
|
||||
$subPage += 'ColorSchemes_Edit'
|
||||
}
|
||||
else
|
||||
{
|
||||
$subPage += 'None'
|
||||
}
|
||||
|
||||
# Register top-level pages
|
||||
if ($filename -eq 'Launch.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Launch/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Launch/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"Launch_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'Interaction.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Interaction/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Interaction/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"Interaction_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'GlobalAppearance.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Appearance/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Appearance/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"GlobalAppearance_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'ColorSchemes.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_ColorSchemes/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_ColorSchemes/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"ColorSchemes_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
|
||||
# Manually register the "add new" button
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"ColorScheme_AddNewButton/Text`""
|
||||
DisplayTextLocalized = 'RS_(L"ColorScheme_AddNewButton/Text")'
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"ColorSchemes_Nav`"})"
|
||||
SubPage = 'BreadcrumbSubPage::None'
|
||||
ElementName = 'L"AddNewButton"'
|
||||
File = $filename
|
||||
}
|
||||
|
||||
}
|
||||
elseif ($filename -eq 'Rendering.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Rendering/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Rendering/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"Rendering_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'Compatibility.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Compatibility/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Compatibility/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"Compatibility_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'Actions.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Actions/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Actions/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"Actions_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'NewTabMenu.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_NewTabMenu/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_NewTabMenu/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"NewTabMenu_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'Extensions.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_Extensions/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_Extensions/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"Extensions_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'Profiles_Base.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_ProfileDefaults/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_ProfileDefaults/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"GlobalProfile_Nav`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
elseif ($filename -eq 'AddProfile.xaml')
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"Nav_AddNewProfile/Content`""
|
||||
DisplayTextLocalized = "RS_(L`"Nav_AddNewProfile/Content`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"AddProfile`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L""'
|
||||
File = $filename
|
||||
}
|
||||
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"AddProfile_AddNewTextBlock/Text`""
|
||||
DisplayTextLocalized = "RS_(L`"AddProfile_AddNewTextBlock/Text`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = "winrt::box_value(hstring{L`"AddProfile`"})"
|
||||
SubPage = "BreadcrumbSubPage::None"
|
||||
ElementName = 'L"AddNewButton"'
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
|
||||
# Find all local:SettingContainer start tags
|
||||
$pattern = '<local:SettingContainer\b([^>/]*)(/?>)'
|
||||
$matchesAll = [System.Text.RegularExpressions.Regex]::Matches($text, $pattern, 'IgnoreCase')
|
||||
|
||||
foreach ($m in $matchesAll)
|
||||
{
|
||||
$attrBlock = $m.Groups[1].Value
|
||||
|
||||
# Extract Uid
|
||||
if ($attrBlock -match '\bx:Uid="([^"]+)"')
|
||||
{
|
||||
$uid = $matches[1]
|
||||
|
||||
# Skip entry if UID prohibited
|
||||
if ($ProhibitedUids -contains $uid)
|
||||
{
|
||||
continue
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
# Extract Name
|
||||
if ($attrBlock -match '\bx:Name="([^"]+)"')
|
||||
{
|
||||
$name = $matches[1]
|
||||
}
|
||||
elseif ($attrBlock -match '\bName="([^"]+)"')
|
||||
{
|
||||
$name = $matches[1]
|
||||
}
|
||||
else
|
||||
{
|
||||
$name = ""
|
||||
}
|
||||
|
||||
# Profile.Appearance settings need a special prefix for the ElementName.
|
||||
# This allows us to bring the element into view at runtime.
|
||||
if ($filename -eq 'Appearances.xaml')
|
||||
{
|
||||
$name = 'App.' + $name
|
||||
}
|
||||
|
||||
# Deduce NavigationParam
|
||||
# includeInBuildIndex: include the entry in the build-time index (no special param at runtime)
|
||||
# includeInPartialIndex: include the entry in the partial index, where the NavigationParam is the view model at runtime (i.e. profile vs profile defaults)
|
||||
$includeInBuildIndex = $true
|
||||
$includeInPartialIndex = $false
|
||||
$navigationParam = 'nullptr'
|
||||
if ($pageClass -match 'Editor::Launch')
|
||||
{
|
||||
$navigationParam = 'Launch_Nav'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Interaction')
|
||||
{
|
||||
$navigationParam = 'Interaction_Nav'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Rendering')
|
||||
{
|
||||
$navigationParam = 'Rendering_Nav'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Compatibility')
|
||||
{
|
||||
$navigationParam = 'Compatibility_Nav'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Actions')
|
||||
{
|
||||
$navigationParam = 'Actions_Nav'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::NewTabMenu')
|
||||
{
|
||||
if ($uid -match 'NewTabMenu_CurrentFolder')
|
||||
{
|
||||
$navigationParam = 'nullptr'
|
||||
$subPage = 'BreadcrumbSubPage::NewTabMenu_Folder'
|
||||
}
|
||||
else
|
||||
{
|
||||
$navigationParam = 'NewTabMenu_Nav'
|
||||
$subPage = 'BreadcrumbSubPage::None'
|
||||
$includeInPartialIndex = $true
|
||||
}
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Extensions')
|
||||
{
|
||||
$navigationParam = 'Extensions_Nav'
|
||||
$subPage = 'BreadcrumbSubPage::None'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::Profiles_Base' -or
|
||||
$pageClass -match 'Editor::Profiles_Appearance' -or
|
||||
$pageClass -match 'Editor::Profiles_Terminal' -or
|
||||
$pageClass -match 'Editor::Profiles_Advanced')
|
||||
{
|
||||
$navigationParam = 'GlobalProfile_Nav'
|
||||
$includeInBuildIndex = !($name -eq "Name" -or $name -eq "Commandline")
|
||||
$includeInPartialIndex = $true
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::EditColorScheme')
|
||||
{
|
||||
# populate with color scheme name at runtime
|
||||
$navigationParam = 'nullptr'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::GlobalAppearance')
|
||||
{
|
||||
$navigationParam = 'GlobalAppearance_Nav'
|
||||
}
|
||||
elseif ($pageClass -match 'Editor::AddProfile')
|
||||
{
|
||||
$navigationParam = 'AddProfile'
|
||||
}
|
||||
|
||||
if ($includeInBuildIndex)
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"$($uid)/Header`""
|
||||
DisplayTextLocalized = "RS_(L`"$($uid)/Header`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = $navigationParam -eq "nullptr" ? $navigationParam : "winrt::box_value(hstring{L`"$($navigationParam)`"})"
|
||||
SubPage = $subPage
|
||||
ElementName = "L`"$($name)`""
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
|
||||
if ($includeInPartialIndex)
|
||||
{
|
||||
$entries += [pscustomobject]@{
|
||||
DisplayTextUid = "L`"$($uid)/Header`""
|
||||
DisplayTextLocalized = "RS_(L`"$($uid)/Header`")"
|
||||
ParentPage = $pageClass
|
||||
NavigationParam = 'nullptr' # VM param at runtime
|
||||
SubPage = $navigationParam -eq 'NewTabMenu_Nav' ? 'BreadcrumbSubPage::NewTabMenu_Folder' : $subPage
|
||||
ElementName = "L`"$($name)`""
|
||||
File = $filename
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure there aren't any duplicate entries
|
||||
$entries = $entries | Sort-Object DisplayTextLocalized, ParentPage, NavigationParam, SubPage, ElementName, File -Unique
|
||||
|
||||
$buildTimeEntries = @()
|
||||
$profileEntries = @()
|
||||
$schemeEntries = @()
|
||||
$ntmEntries = @()
|
||||
foreach ($e in $entries)
|
||||
{
|
||||
$formattedEntry = " IndexEntry{ $($e.DisplayTextUid), $($e.DisplayTextLocalized), $($e.NavigationParam), $($e.SubPage), $($e.ElementName) }, // $($e.File)"
|
||||
|
||||
if ($e.NavigationParam -eq 'nullptr' -and
|
||||
($e.ParentPage -match 'Profiles_Base' -or
|
||||
$e.ParentPage -match 'Profiles_Appearance' -or
|
||||
$e.ParentPage -match 'Profiles_Terminal' -or
|
||||
$e.ParentPage -match 'Profiles_Advanced'))
|
||||
{
|
||||
$profileEntries += $formattedEntry
|
||||
}
|
||||
elseif ($e.SubPage -eq 'BreadcrumbSubPage::ColorSchemes_Edit')
|
||||
{
|
||||
$schemeEntries += $formattedEntry
|
||||
}
|
||||
elseif ($e.SubPage -eq 'BreadcrumbSubPage::NewTabMenu_Folder')
|
||||
{
|
||||
$ntmEntries += $formattedEntry
|
||||
}
|
||||
else
|
||||
{
|
||||
$buildTimeEntries += $formattedEntry
|
||||
}
|
||||
}
|
||||
|
||||
$headerPath = Join-Path $OutputDir 'GeneratedSettingsIndex.g.h'
|
||||
$cppPath = Join-Path $OutputDir 'GeneratedSettingsIndex.g.cpp'
|
||||
|
||||
$header = @"
|
||||
/*++
|
||||
Copyright (c) Microsoft Corporation
|
||||
Licensed under the MIT license.
|
||||
--*/
|
||||
#pragma once
|
||||
#include <winrt/Windows.UI.Xaml.Interop.h>
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
struct IndexEntry
|
||||
{
|
||||
// x:Uid of the SettingContainer's Header (i.e. "Globals_DefaultProfile/Header")
|
||||
hstring DisplayTextUid;
|
||||
|
||||
// Localized display text shown in the SettingContainer (i.e. RS_(L"Globals_DefaultProfile/Header"))
|
||||
hstring DisplayTextLocalized;
|
||||
|
||||
// Navigation argument (i.e. winrt::box_value(hstring) or nullptr)
|
||||
// Use nullptr as placeholder for runtime navigation with a view model object
|
||||
winrt::Windows::Foundation::IInspectable NavigationArg;
|
||||
|
||||
BreadcrumbSubPage SubPage;
|
||||
|
||||
// x:Name of the SettingContainer to navigate to on the page (i.e. "DefaultProfile")
|
||||
hstring ElementName;
|
||||
};
|
||||
|
||||
const std::array<IndexEntry, $($buildTimeEntries.Count)>& LoadBuildTimeIndex();
|
||||
const std::array<IndexEntry, $($profileEntries.Count)>& LoadProfileIndex();
|
||||
const std::array<IndexEntry, $($ntmEntries.Count)>& LoadNTMFolderIndex();
|
||||
const std::array<IndexEntry, $($schemeEntries.Count)>& LoadColorSchemeIndex();
|
||||
|
||||
const IndexEntry& PartialProfileIndexEntry();
|
||||
const IndexEntry& PartialNTMFolderIndexEntry();
|
||||
const IndexEntry& PartialColorSchemeIndexEntry();
|
||||
const IndexEntry& PartialExtensionIndexEntry();
|
||||
const IndexEntry& PartialActionIndexEntry();
|
||||
}
|
||||
"@
|
||||
|
||||
$cpp = @"
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
#include "pch.h"
|
||||
#include <winrt/Microsoft.Terminal.Settings.Editor.h>
|
||||
#include "GeneratedSettingsIndex.g.h"
|
||||
#include <LibraryResources.h>
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
{
|
||||
const std::array<IndexEntry, $($buildTimeEntries.Count)>& LoadBuildTimeIndex()
|
||||
{
|
||||
static std::array<IndexEntry, $($buildTimeEntries.Count)> entries =
|
||||
{
|
||||
$( ($buildTimeEntries -join "`r`n") )
|
||||
};
|
||||
return entries;
|
||||
}
|
||||
|
||||
const std::array<IndexEntry, $($profileEntries.Count)>& LoadProfileIndex()
|
||||
{
|
||||
static std::array<IndexEntry, $($profileEntries.Count)> entries =
|
||||
{
|
||||
$( ($profileEntries -join "`r`n") )
|
||||
};
|
||||
return entries;
|
||||
}
|
||||
|
||||
const std::array<IndexEntry, $($ntmEntries.Count)>& LoadNTMFolderIndex()
|
||||
{
|
||||
static std::array<IndexEntry, $($ntmEntries.Count)> entries =
|
||||
{
|
||||
$( ($ntmEntries -join "`r`n") )
|
||||
};
|
||||
return entries;
|
||||
}
|
||||
|
||||
const std::array<IndexEntry, $($schemeEntries.Count)>& LoadColorSchemeIndex()
|
||||
{
|
||||
static std::array<IndexEntry, $($schemeEntries.Count)> entries =
|
||||
{
|
||||
$( ($schemeEntries -join "`r`n") )
|
||||
};
|
||||
return entries;
|
||||
}
|
||||
|
||||
const IndexEntry& PartialProfileIndexEntry()
|
||||
{
|
||||
static IndexEntry entry{ L"", L"", nullptr, BreadcrumbSubPage::None, L"" };
|
||||
return entry;
|
||||
}
|
||||
|
||||
const IndexEntry& PartialNTMFolderIndexEntry()
|
||||
{
|
||||
static IndexEntry entry{ L"", L"", nullptr, BreadcrumbSubPage::NewTabMenu_Folder, L"" };
|
||||
return entry;
|
||||
}
|
||||
|
||||
const IndexEntry& PartialColorSchemeIndexEntry()
|
||||
{
|
||||
static IndexEntry entry{ L"", L"", nullptr, BreadcrumbSubPage::ColorSchemes_Edit, L"" };
|
||||
return entry;
|
||||
}
|
||||
|
||||
const IndexEntry& PartialExtensionIndexEntry()
|
||||
{
|
||||
static IndexEntry entry{ L"", L"", nullptr, BreadcrumbSubPage::Extensions_Extension, L"" };
|
||||
return entry;
|
||||
}
|
||||
|
||||
const IndexEntry& PartialActionIndexEntry()
|
||||
{
|
||||
static IndexEntry entry{ L"", L"", nullptr, BreadcrumbSubPage::Actions_Edit, L"" };
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
Set-Content -LiteralPath $headerPath -Value $header -NoNewline
|
||||
Set-Content -LiteralPath $cppPath -Value $cpp -NoNewline
|
||||
|
||||
Write-Host "Generated:"
|
||||
Write-Host " $headerPath"
|
||||
Write-Host " $cppPath"
|
||||
Reference in New Issue
Block a user