Skip to content

Commit bfee6f0

Browse files
committed
Replace New Tab Menu Match Profiles functionality with regex support
1 parent 3760cae commit bfee6f0

File tree

8 files changed

+82
-7
lines changed

8 files changed

+82
-7
lines changed

Diff for: src/cascadia/TerminalApp/Resources/en-US/Resources.resw

+3
Original file line numberDiff line numberDiff line change
@@ -944,4 +944,7 @@
944944
<data name="TabMoveRight" xml:space="preserve">
945945
<value>Move right</value>
946946
</data>
947+
<data name="InvalidRegex" xml:space="preserve">
948+
<value>An invalid regex was found.</value>
949+
</data>
947950
</root>

Diff for: src/cascadia/TerminalApp/TerminalWindow.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static const std::array settingsLoadWarningsLabels{
5555
USES_RESOURCE(L"UnknownTheme"),
5656
USES_RESOURCE(L"DuplicateRemainingProfilesEntry"),
5757
USES_RESOURCE(L"InvalidUseOfContent"),
58+
USES_RESOURCE(L"InvalidRegex"),
5859
};
5960

6061
static_assert(settingsLoadWarningsLabels.size() == static_cast<size_t>(SettingsLoadWarnings::WARNINGS_SIZE));

Diff for: src/cascadia/TerminalSettingsEditor/NewTabMenu.xaml

+2
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,8 @@
449449
FontIconGlyph="&#xE748;"
450450
Style="{StaticResource ExpanderSettingContainerStyleWithIcon}">
451451
<StackPanel Spacing="10">
452+
<HyperlinkButton x:Uid="NewTabMenu_AddMatchProfiles_Help"
453+
NavigateUri="https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference" />
452454
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Name"
453455
Text="{x:Bind ViewModel.ProfileMatcherName, Mode=TwoWay}" />
454456
<TextBox x:Uid="NewTabMenu_AddMatchProfiles_Source"

Diff for: src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw

+7-4
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,7 @@
21052105
<comment>Header for a control that adds any remaining profiles to the new tab menu.</comment>
21062106
</data>
21072107
<data name="NewTabMenu_AddMatchProfiles.HelpText" xml:space="preserve">
2108-
<value>Add a group of profiles that match at least one of the defined properties</value>
2108+
<value>Add a group of profiles that match at least one of the defined regex properties</value>
21092109
<comment>Additional information for a control that adds a terminal profile matcher to the new tab menu. Presented near "NewTabMenu_AddMatchProfiles".</comment>
21102110
</data>
21112111
<data name="NewTabMenu_AddRemainingProfiles.HelpText" xml:space="preserve">
@@ -2121,15 +2121,15 @@
21212121
<comment>Header for a control that adds a folder to the new tab menu.</comment>
21222122
</data>
21232123
<data name="NewTabMenu_AddMatchProfiles_Name.Header" xml:space="preserve">
2124-
<value>Profile name</value>
2124+
<value>Profile name (Regex)</value>
21252125
<comment>Header for a text box used to define a regex for the names of profiles to add.</comment>
21262126
</data>
21272127
<data name="NewTabMenu_AddMatchProfiles_Source.Header" xml:space="preserve">
2128-
<value>Profile source</value>
2128+
<value>Profile source (Regex)</value>
21292129
<comment>Header for a text box used to define a regex for the sources of profiles to add.</comment>
21302130
</data>
21312131
<data name="NewTabMenu_AddMatchProfiles_Commandline.Header" xml:space="preserve">
2132-
<value>Commandline</value>
2132+
<value>Commandline (Regex)</value>
21332133
<comment>Header for a text box used to define a regex for the commandlines of profiles to add.</comment>
21342134
</data>
21352135
<data name="NewTabMenu_AddMatchProfilesTextBlock.Text" xml:space="preserve">
@@ -2340,4 +2340,7 @@
23402340
<value>This option is managed by enterprise policy and cannot be changed here.</value>
23412341
<comment>This is displayed in concordance with Globals_StartOnUserLogin if the enterprise administrator has taken control of this setting.</comment>
23422342
</data>
2343+
<data name="NewTabMenu_AddMatchProfiles_Help.Content" xml:space="preserve">
2344+
<value>Learn more about regular expressions</value>
2345+
</data>
23432346
</root>

Diff for: src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ void CascadiaSettings::_validateSettings()
429429
_validateColorSchemesInCommands();
430430
_validateThemeExists();
431431
_validateProfileEnvironmentVariables();
432+
_validateRegexes();
432433
}
433434

434435
// Method Description:
@@ -583,6 +584,49 @@ void CascadiaSettings::_validateProfileEnvironmentVariables()
583584
}
584585
}
585586

587+
static void _validateRegex(const winrt::hstring& regex, IVector<Model::SettingsLoadWarnings>& warnings)
588+
{
589+
try
590+
{
591+
std::wregex{ regex.cbegin(), regex.cend() };
592+
}
593+
catch (std::regex_error)
594+
{
595+
warnings.Append(Model::SettingsLoadWarnings::InvalidRegex);
596+
}
597+
}
598+
599+
static void _validateNTMEntries(const IVector<Model::NewTabMenuEntry>& entries, IVector<Model::SettingsLoadWarnings>& warnings)
600+
{
601+
for (const auto& ntmEntry : entries)
602+
{
603+
if (const auto& folderEntry = ntmEntry.try_as<Model::FolderEntry>())
604+
{
605+
_validateNTMEntries(folderEntry.RawEntries(), warnings);
606+
}
607+
if (const auto& matchProfilesEntry = ntmEntry.try_as<Model::MatchProfilesEntry>())
608+
{
609+
if (const auto nameRegex = matchProfilesEntry.Name(); !nameRegex.empty())
610+
{
611+
_validateRegex(nameRegex, warnings);
612+
}
613+
if (const auto commandlineRegex = matchProfilesEntry.Commandline(); !commandlineRegex.empty())
614+
{
615+
_validateRegex(commandlineRegex, warnings);
616+
}
617+
if (const auto sourceRegex = matchProfilesEntry.Source(); !sourceRegex.empty())
618+
{
619+
_validateRegex(sourceRegex, warnings);
620+
}
621+
}
622+
}
623+
}
624+
625+
void CascadiaSettings::_validateRegexes()
626+
{
627+
_validateNTMEntries(_globals->NewTabMenu(), _warnings);
628+
}
629+
586630
// Method Description:
587631
// - Helper to get the GUID of a profile, given an optional index and a possible
588632
// "profile" value to override that.

Diff for: src/cascadia/TerminalSettingsModel/CascadiaSettings.h

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
175175
void _validateColorSchemesInCommands() const;
176176
bool _hasInvalidColorScheme(const Model::Command& command) const;
177177
void _validateThemeExists();
178+
void _validateRegexes();
178179

179180
void _researchOnLoad();
180181

Diff for: src/cascadia/TerminalSettingsModel/MatchProfilesEntry.cpp

+23-3
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,39 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
5555
// value of the function we consider the null value to be "false".
5656
auto isMatching = std::optional<bool>{};
5757

58+
auto isMatch = [](std::wstring_view regex, std::wstring_view text) {
59+
if (text.empty())
60+
{
61+
return false;
62+
}
63+
64+
std::wregex re;
65+
try
66+
{
67+
re = { regex.cbegin(), regex.cend() };
68+
}
69+
catch (std::regex_error)
70+
{
71+
// invalid regex
72+
return false;
73+
}
74+
75+
return std::regex_match(text.cbegin(), text.cend(), re);
76+
};
77+
5878
if (!_Name.empty())
5979
{
60-
isMatching = { isMatching.value_or(true) && _Name == profile.Name() };
80+
isMatching = { isMatching.value_or(true) && isMatch(_Name, profile.Name()) };
6181
}
6282

6383
if (!_Source.empty())
6484
{
65-
isMatching = { isMatching.value_or(true) && _Source == profile.Source() };
85+
isMatching = { isMatching.value_or(true) && isMatch(_Source, profile.Source()) };
6686
}
6787

6888
if (!_Commandline.empty())
6989
{
70-
isMatching = { isMatching.value_or(true) && _Commandline == profile.Commandline() };
90+
isMatching = { isMatching.value_or(true) && isMatch(_Commandline, profile.Commandline()) };
7191
}
7292

7393
return isMatching.value_or(false);

Diff for: src/cascadia/TerminalSettingsModel/TerminalWarnings.idl

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace Microsoft.Terminal.Settings.Model
2525
UnknownTheme,
2626
DuplicateRemainingProfilesEntry,
2727
InvalidUseOfContent,
28+
InvalidRegex,
2829
WARNINGS_SIZE // IMPORTANT: This MUST be the last value in this enum. It's an unused placeholder.
2930
};
3031

0 commit comments

Comments
 (0)