mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 13:36:29 -06:00
When the profile icon is set to null, fall back to the icon of the commandline (#15843)
Basically, title. If you null out the icon, we'll automatically try to use the `commandline` as an icon (because we can now). We'll even be smart about it - `cmd.exe /k echo wassup` will still just use the ico of `cmd.exe`. This doesn't work for `ubuntu.exe` (et. al), because that commandline is technically a reparse point, that doesn't actually have an icon associated with it. Closes #705 `"none"` becomes our sentinel value for "no icon". This will also use the same `NormalizeCommandLine` we use for commandline matching for finding the full path to the exe.
This commit is contained in:
parent
fefee50757
commit
4ff38c260f
@ -173,13 +173,13 @@ namespace SettingsModelLocalTests
|
|||||||
{
|
{
|
||||||
const auto commandLine = file2.native() + LR"( -foo "bar1 bar2" -baz)"s;
|
const auto commandLine = file2.native() + LR"( -foo "bar1 bar2" -baz)"s;
|
||||||
const auto expected = file2.native() + L"\0-foo\0bar1 bar2\0-baz"s;
|
const auto expected = file2.native() + L"\0-foo\0bar1 bar2\0-baz"s;
|
||||||
const auto actual = implementation::CascadiaSettings::NormalizeCommandLine(commandLine.c_str());
|
const auto actual = implementation::Profile::NormalizeCommandLine(commandLine.c_str());
|
||||||
VERIFY_ARE_EQUAL(expected, actual);
|
VERIFY_ARE_EQUAL(expected, actual);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const auto commandLine = L"C:\\";
|
const auto commandLine = L"C:\\";
|
||||||
const auto expected = L"C:\\";
|
const auto expected = L"C:\\";
|
||||||
const auto actual = implementation::CascadiaSettings::NormalizeCommandLine(commandLine);
|
const auto actual = implementation::Profile::NormalizeCommandLine(commandLine);
|
||||||
VERIFY_ARE_EQUAL(expected, actual);
|
VERIFY_ARE_EQUAL(expected, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -174,11 +174,12 @@ namespace winrt::TerminalApp::implementation
|
|||||||
// Set this tab's icon to the icon from the user's profile
|
// Set this tab's icon to the icon from the user's profile
|
||||||
if (const auto profile{ newTabImpl->GetFocusedProfile() })
|
if (const auto profile{ newTabImpl->GetFocusedProfile() })
|
||||||
{
|
{
|
||||||
if (!profile.Icon().empty())
|
const auto& icon = profile.EvaluatedIcon();
|
||||||
|
if (!icon.empty())
|
||||||
{
|
{
|
||||||
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
||||||
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
|
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
|
||||||
newTabImpl->UpdateIcon(profile.Icon(), iconStyle);
|
newTabImpl->UpdateIcon(icon, iconStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +246,7 @@ namespace winrt::TerminalApp::implementation
|
|||||||
{
|
{
|
||||||
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
const auto theme = _settings.GlobalSettings().CurrentTheme();
|
||||||
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
|
const auto iconStyle = (theme && theme.Tab()) ? theme.Tab().IconStyle() : IconStyle::Default;
|
||||||
tab.UpdateIcon(profile.Icon(), iconStyle);
|
tab.UpdateIcon(profile.EvaluatedIcon(), iconStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1033,9 +1033,10 @@ namespace winrt::TerminalApp::implementation
|
|||||||
|
|
||||||
// If there's an icon set for this profile, set it as the icon for
|
// If there's an icon set for this profile, set it as the icon for
|
||||||
// this flyout item
|
// this flyout item
|
||||||
if (!profile.Icon().empty())
|
const auto& iconPath = profile.EvaluatedIcon();
|
||||||
|
if (!iconPath.empty())
|
||||||
{
|
{
|
||||||
const auto icon = _CreateNewTabFlyoutIcon(profile.Icon());
|
const auto icon = _CreateNewTabFlyoutIcon(iconPath);
|
||||||
profileMenuItem.Icon(icon);
|
profileMenuItem.Icon(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -602,7 +602,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
MUX::Controls::NavigationViewItem profileNavItem;
|
MUX::Controls::NavigationViewItem profileNavItem;
|
||||||
profileNavItem.Content(box_value(profile.Name()));
|
profileNavItem.Content(box_value(profile.Name()));
|
||||||
profileNavItem.Tag(box_value<Editor::ProfileViewModel>(profile));
|
profileNavItem.Tag(box_value<Editor::ProfileViewModel>(profile));
|
||||||
profileNavItem.Icon(IconPathConverter::IconWUX(profile.Icon()));
|
profileNavItem.Icon(IconPathConverter::IconWUX(profile.EvaluatedIcon()));
|
||||||
|
|
||||||
// Update the menu item when the icon/name changes
|
// Update the menu item when the icon/name changes
|
||||||
auto weakMenuItem{ make_weak(profileNavItem) };
|
auto weakMenuItem{ make_weak(profileNavItem) };
|
||||||
|
|||||||
@ -26,6 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
|
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
|
||||||
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
|
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_FontList{ nullptr };
|
||||||
|
|
||||||
|
static constexpr std::wstring_view HideIconValue{ L"none" };
|
||||||
|
|
||||||
ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings) :
|
ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings) :
|
||||||
_profile{ profile },
|
_profile{ profile },
|
||||||
_defaultAppearanceViewModel{ winrt::make<implementation::AppearanceViewModel>(profile.DefaultAppearance().try_as<AppearanceConfig>()) },
|
_defaultAppearanceViewModel{ winrt::make<implementation::AppearanceViewModel>(profile.DefaultAppearance().try_as<AppearanceConfig>()) },
|
||||||
@ -69,6 +71,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
{
|
{
|
||||||
_NotifyChanges(L"CurrentScrollState");
|
_NotifyChanges(L"CurrentScrollState");
|
||||||
}
|
}
|
||||||
|
else if (viewModelProperty == L"Icon")
|
||||||
|
{
|
||||||
|
_NotifyChanges(L"HideIcon");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do the same for the starting directory
|
// Do the same for the starting directory
|
||||||
@ -348,6 +354,26 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProfileViewModel::HideIcon()
|
||||||
|
{
|
||||||
|
return Icon() == HideIconValue;
|
||||||
|
}
|
||||||
|
void ProfileViewModel::HideIcon(const bool hide)
|
||||||
|
{
|
||||||
|
if (hide)
|
||||||
|
{
|
||||||
|
// Stash the current value of Icon. If the user
|
||||||
|
// checks and un-checks the "Hide Icon" checkbox, we want
|
||||||
|
// the path that we display in the text box to remain unchanged.
|
||||||
|
_lastIcon = Icon();
|
||||||
|
Icon(HideIconValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Icon(_lastIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ProfileViewModel::IsBellStyleFlagSet(const uint32_t flag)
|
bool ProfileViewModel::IsBellStyleFlagSet(const uint32_t flag)
|
||||||
{
|
{
|
||||||
return (WI_EnumValue(BellStyle()) & flag) == flag;
|
return (WI_EnumValue(BellStyle()) & flag) == flag;
|
||||||
|
|||||||
@ -58,11 +58,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
Padding(to_hstring(value));
|
Padding(to_hstring(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
winrt::hstring EvaluatedIcon() const
|
||||||
|
{
|
||||||
|
return _profile.EvaluatedIcon();
|
||||||
|
}
|
||||||
|
|
||||||
// starting directory
|
// starting directory
|
||||||
bool UseParentProcessDirectory();
|
bool UseParentProcessDirectory();
|
||||||
void UseParentProcessDirectory(const bool useParent);
|
void UseParentProcessDirectory(const bool useParent);
|
||||||
bool UseCustomStartingDirectory();
|
bool UseCustomStartingDirectory();
|
||||||
|
|
||||||
|
// icon
|
||||||
|
bool HideIcon();
|
||||||
|
void HideIcon(const bool hide);
|
||||||
|
|
||||||
// general profile knowledge
|
// general profile knowledge
|
||||||
winrt::guid OriginalProfileGuid() const noexcept;
|
winrt::guid OriginalProfileGuid() const noexcept;
|
||||||
bool CanDeleteProfile() const;
|
bool CanDeleteProfile() const;
|
||||||
@ -119,6 +128,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|||||||
winrt::guid _originalProfileGuid{};
|
winrt::guid _originalProfileGuid{};
|
||||||
winrt::hstring _lastBgImagePath;
|
winrt::hstring _lastBgImagePath;
|
||||||
winrt::hstring _lastStartingDirectoryPath;
|
winrt::hstring _lastStartingDirectoryPath;
|
||||||
|
winrt::hstring _lastIcon;
|
||||||
Editor::AppearanceViewModel _defaultAppearanceViewModel;
|
Editor::AppearanceViewModel _defaultAppearanceViewModel;
|
||||||
|
|
||||||
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
|
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
|
||||||
|
|||||||
@ -67,6 +67,7 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||||||
ProfileSubPage CurrentPage;
|
ProfileSubPage CurrentPage;
|
||||||
Boolean UseParentProcessDirectory;
|
Boolean UseParentProcessDirectory;
|
||||||
Boolean UseCustomStartingDirectory { get; };
|
Boolean UseCustomStartingDirectory { get; };
|
||||||
|
Boolean HideIcon;
|
||||||
AppearanceViewModel DefaultAppearance { get; };
|
AppearanceViewModel DefaultAppearance { get; };
|
||||||
Guid OriginalProfileGuid { get; };
|
Guid OriginalProfileGuid { get; };
|
||||||
Boolean HasUnfocusedAppearance { get; };
|
Boolean HasUnfocusedAppearance { get; };
|
||||||
@ -75,6 +76,8 @@ namespace Microsoft.Terminal.Settings.Editor
|
|||||||
AppearanceViewModel UnfocusedAppearance { get; };
|
AppearanceViewModel UnfocusedAppearance { get; };
|
||||||
Boolean VtPassthroughAvailable { get; };
|
Boolean VtPassthroughAvailable { get; };
|
||||||
|
|
||||||
|
String EvaluatedIcon { get; };
|
||||||
|
|
||||||
void CreateUnfocusedAppearance();
|
void CreateUnfocusedAppearance();
|
||||||
void DeleteUnfocusedAppearance();
|
void DeleteUnfocusedAppearance();
|
||||||
|
|
||||||
|
|||||||
@ -108,13 +108,20 @@
|
|||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBox x:Uid="Profile_IconBox"
|
<TextBox x:Uid="Profile_IconBox"
|
||||||
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
FontFamily="Segoe UI, Segoe Fluent Icons, Segoe MDL2 Assets"
|
||||||
|
IsEnabled="{x:Bind local:Converters.InvertBoolean(Profile.HideIcon), Mode=OneWay}"
|
||||||
IsSpellCheckEnabled="False"
|
IsSpellCheckEnabled="False"
|
||||||
Style="{StaticResource TextBoxSettingStyle}"
|
Style="{StaticResource TextBoxSettingStyle}"
|
||||||
Text="{x:Bind Profile.Icon, Mode=TwoWay}" />
|
Text="{x:Bind Profile.Icon, Mode=TwoWay}"
|
||||||
|
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.HideIcon), Mode=OneWay}" />
|
||||||
<Button x:Uid="Profile_IconBrowse"
|
<Button x:Uid="Profile_IconBrowse"
|
||||||
Margin="0,10,0,0"
|
Margin="0,10,0,0"
|
||||||
Click="Icon_Click"
|
Click="Icon_Click"
|
||||||
Style="{StaticResource BrowseButtonStyle}" />
|
Style="{StaticResource BrowseButtonStyle}"
|
||||||
|
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(Profile.HideIcon), Mode=OneWay}" />
|
||||||
|
<CheckBox x:Name="HideIconCheckbox"
|
||||||
|
x:Uid="Profile_HideIconCheckbox"
|
||||||
|
Margin="0,5,0,0"
|
||||||
|
IsChecked="{x:Bind Profile.HideIcon, Mode=TwoWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</local:SettingContainer>
|
</local:SettingContainer>
|
||||||
|
|
||||||
|
|||||||
@ -1042,6 +1042,14 @@
|
|||||||
<value>If enabled, this profile will spawn in the directory from which Terminal was launched.</value>
|
<value>If enabled, this profile will spawn in the directory from which Terminal was launched.</value>
|
||||||
<comment>A description for what the supplementary "use parent process directory" setting does. Presented near "Profile_StartingDirectoryUseParentCheckbox".</comment>
|
<comment>A description for what the supplementary "use parent process directory" setting does. Presented near "Profile_StartingDirectoryUseParentCheckbox".</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Profile_HideIconCheckbox.Content" xml:space="preserve">
|
||||||
|
<value>Hide icon</value>
|
||||||
|
<comment>A supplementary setting to the "icon" setting.</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Profile_HideIconCheckbox.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||||
|
<value>If enabled, this profile will have no icon.</value>
|
||||||
|
<comment>A description for what the supplementary "Hide icon" setting does. Presented near "Profile_HideIconCheckbox".</comment>
|
||||||
|
</data>
|
||||||
<data name="Profile_SuppressApplicationTitle.Header" xml:space="preserve">
|
<data name="Profile_SuppressApplicationTitle.Header" xml:space="preserve">
|
||||||
<value>Suppress title changes</value>
|
<value>Suppress title changes</value>
|
||||||
<comment>Header for a control to toggle changes in the app title.</comment>
|
<comment>Header for a control to toggle changes in the app title.</comment>
|
||||||
|
|||||||
@ -299,6 +299,7 @@ Model::Profile CascadiaSettings::DuplicateProfile(const Model::Profile& source)
|
|||||||
// These aren't in MTSM_PROFILE_SETTINGS because they're special
|
// These aren't in MTSM_PROFILE_SETTINGS because they're special
|
||||||
DUPLICATE_SETTING_MACRO(TabColor);
|
DUPLICATE_SETTING_MACRO(TabColor);
|
||||||
DUPLICATE_SETTING_MACRO(Padding);
|
DUPLICATE_SETTING_MACRO(Padding);
|
||||||
|
DUPLICATE_SETTING_MACRO(Icon);
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto font = source.FontInfo();
|
const auto font = source.FontInfo();
|
||||||
@ -515,8 +516,12 @@ void CascadiaSettings::_validateMediaResources()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anything longer than 2 wchar_t's _isn't_ an emoji or symbol,
|
// Anything longer than 2 wchar_t's _isn't_ an emoji or symbol, so treat
|
||||||
// so treat it as an invalid path.
|
// it as an invalid path.
|
||||||
|
//
|
||||||
|
// Explicitly just use the Icon here, not the EvaluatedIcon. We don't
|
||||||
|
// want to blow up if we fell back to the commandline and the
|
||||||
|
// commandline _isn't an icon_.
|
||||||
if (const auto icon = profile.Icon(); icon.size() > 2)
|
if (const auto icon = profile.Icon(); icon.size() > 2)
|
||||||
{
|
{
|
||||||
const auto iconPath{ wil::ExpandEnvironmentStringsW<std::wstring>(icon.c_str()) };
|
const auto iconPath{ wil::ExpandEnvironmentStringsW<std::wstring>(icon.c_str()) };
|
||||||
@ -662,7 +667,7 @@ Model::Profile CascadiaSettings::_getProfileForCommandLine(const winrt::hstring&
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_commandLinesCache.emplace_back(NormalizeCommandLine(cmd.c_str()), profile);
|
_commandLinesCache.emplace_back(Profile::NormalizeCommandLine(cmd.c_str()), profile);
|
||||||
}
|
}
|
||||||
CATCH_LOG()
|
CATCH_LOG()
|
||||||
}
|
}
|
||||||
@ -681,7 +686,7 @@ Model::Profile CascadiaSettings::_getProfileForCommandLine(const winrt::hstring&
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const auto needle = NormalizeCommandLine(commandLine.c_str());
|
const auto needle = Profile::NormalizeCommandLine(commandLine.c_str());
|
||||||
|
|
||||||
// til::starts_with(string, prefix) will always return false if prefix.size() > string.size().
|
// til::starts_with(string, prefix) will always return false if prefix.size() > string.size().
|
||||||
// --> Using binary search we can safely skip all items in _commandLinesCache where .first.size() > needle.size().
|
// --> Using binary search we can safely skip all items in _commandLinesCache where .first.size() > needle.size().
|
||||||
@ -710,129 +715,6 @@ Model::Profile CascadiaSettings::_getProfileForCommandLine(const winrt::hstring&
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a commandLine like the following:
|
|
||||||
// * "C:\WINDOWS\System32\cmd.exe"
|
|
||||||
// * "pwsh -WorkingDirectory ~"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe -WorkingDirectory ~"
|
|
||||||
//
|
|
||||||
// This function returns:
|
|
||||||
// * "C:\Windows\System32\cmd.exe"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe\0-WorkingDirectory\0~"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe\0-WorkingDirectory\0~"
|
|
||||||
//
|
|
||||||
// The resulting strings are then used for comparisons in _getProfileForCommandLine().
|
|
||||||
// For instance a resulting string of
|
|
||||||
// "C:\Program Files\PowerShell\7\pwsh.exe"
|
|
||||||
// is considered a compatible profile with
|
|
||||||
// "C:\Program Files\PowerShell\7\pwsh.exe -WorkingDirectory ~"
|
|
||||||
// as it shares the same (normalized) prefix.
|
|
||||||
std::wstring CascadiaSettings::NormalizeCommandLine(LPCWSTR commandLine)
|
|
||||||
{
|
|
||||||
// Turn "%SystemRoot%\System32\cmd.exe" into "C:\WINDOWS\System32\cmd.exe".
|
|
||||||
// We do this early, as environment variables might occur anywhere in the commandLine.
|
|
||||||
std::wstring normalized;
|
|
||||||
THROW_IF_FAILED(wil::ExpandEnvironmentStringsW(commandLine, normalized));
|
|
||||||
|
|
||||||
// One of the most important things this function does is to strip quotes.
|
|
||||||
// That way the commandLine "foo.exe -bar" and "\"foo.exe\" \"-bar\"" appear identical.
|
|
||||||
// We'll abuse CommandLineToArgvW for that as it's close to what CreateProcessW uses.
|
|
||||||
auto argc = 0;
|
|
||||||
wil::unique_hlocal_ptr<PWSTR[]> argv{ CommandLineToArgvW(normalized.c_str(), &argc) };
|
|
||||||
THROW_LAST_ERROR_IF(!argc);
|
|
||||||
|
|
||||||
// The index of the first argument in argv for our executable in argv[0].
|
|
||||||
// Given {"C:\Program Files\PowerShell\7\pwsh.exe", "-WorkingDirectory", "~"} this will be 1.
|
|
||||||
auto startOfArguments = 1;
|
|
||||||
|
|
||||||
// The given commandLine should start with an executable name or path.
|
|
||||||
// For instance given the following argv arrays:
|
|
||||||
// * {"C:\WINDOWS\System32\cmd.exe"}
|
|
||||||
// * {"pwsh", "-WorkingDirectory", "~"}
|
|
||||||
// * {"C:\Program", "Files\PowerShell\7\pwsh.exe"}
|
|
||||||
// ^^^^
|
|
||||||
// Notice how there used to be a space in the path, which was split by ExpandEnvironmentStringsW().
|
|
||||||
// CreateProcessW() supports such atrocities, so we got to do the same.
|
|
||||||
// * {"C:\Program Files\PowerShell\7\pwsh.exe", "-WorkingDirectory", "~"}
|
|
||||||
//
|
|
||||||
// This loop tries to resolve relative paths, as well as executable names in %PATH%
|
|
||||||
// into absolute paths and normalizes them. The results for the above would be:
|
|
||||||
// * "C:\Windows\System32\cmd.exe"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
|
||||||
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
// CreateProcessW uses RtlGetExePath to get the lpPath for SearchPathW.
|
|
||||||
// The difference between the behavior of SearchPathW if lpPath is nullptr and what RtlGetExePath returns
|
|
||||||
// seems to be mostly whether SafeProcessSearchMode is respected and the support for relative paths.
|
|
||||||
// Windows Terminal makes the use of relative paths rather impractical which is why we simply dropped the call to RtlGetExePath.
|
|
||||||
const auto status = wil::SearchPathW(nullptr, argv[0], L".exe", normalized);
|
|
||||||
|
|
||||||
if (status == S_OK)
|
|
||||||
{
|
|
||||||
const auto attributes = GetFileAttributesW(normalized.c_str());
|
|
||||||
|
|
||||||
if (attributes != INVALID_FILE_ATTRIBUTES && WI_IsFlagClear(attributes, FILE_ATTRIBUTE_DIRECTORY))
|
|
||||||
{
|
|
||||||
std::filesystem::path path{ std::move(normalized) };
|
|
||||||
|
|
||||||
// canonical() will resolve symlinks, etc. for us.
|
|
||||||
{
|
|
||||||
std::error_code ec;
|
|
||||||
auto canonicalPath = std::filesystem::canonical(path, ec);
|
|
||||||
if (!ec)
|
|
||||||
{
|
|
||||||
path = std::move(canonicalPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::filesystem::path has no way to extract the internal path.
|
|
||||||
// So about that.... I own you, computer. Give me that path.
|
|
||||||
normalized = std::move(const_cast<std::wstring&>(path.native()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// All other error types aren't handled at the moment.
|
|
||||||
else if (status != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// If the file path couldn't be found by SearchPathW this could be the result of us being given a commandLine
|
|
||||||
// like "C:\foo bar\baz.exe -arg" which is resolved to the argv array {"C:\foo", "bar\baz.exe", "-arg"},
|
|
||||||
// or we were erroneously given a directory to execute (e.g. someone ran `wt .`).
|
|
||||||
// Just like CreateProcessW() we thus try to concatenate arguments until we successfully resolve a valid path.
|
|
||||||
// Of course we can only do that if we have at least 2 remaining arguments in argv.
|
|
||||||
if ((argc - startOfArguments) < 2)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As described in the comment right above, we concatenate arguments in an attempt to resolve a valid path.
|
|
||||||
// The code below turns argv from {"C:\foo", "bar\baz.exe", "-arg"} into {"C:\foo bar\baz.exe", "-arg"}.
|
|
||||||
// The code abuses the fact that CommandLineToArgvW allocates all arguments back-to-back on the heap separated by '\0'.
|
|
||||||
argv[startOfArguments][-1] = L' ';
|
|
||||||
++startOfArguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've (hopefully) finished resolving the path to the executable.
|
|
||||||
// We're now going to append all remaining arguments to the resulting string.
|
|
||||||
// If argv is {"C:\Program Files\PowerShell\7\pwsh.exe", "-WorkingDirectory", "~"},
|
|
||||||
// then we'll get "C:\Program Files\PowerShell\7\pwsh.exe\0-WorkingDirectory\0~"
|
|
||||||
if (startOfArguments < argc)
|
|
||||||
{
|
|
||||||
// normalized contains a canonical form of argv[0] at this point.
|
|
||||||
// -1 allows us to include the \0 between argv[0] and argv[1] in the call to append().
|
|
||||||
const auto beg = argv[startOfArguments] - 1;
|
|
||||||
const auto lastArg = argv[argc - 1];
|
|
||||||
const auto end = lastArg + wcslen(lastArg);
|
|
||||||
normalized.append(beg, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
// - Helper to get a profile given a name that could be a guid or an actual name.
|
// - Helper to get a profile given a name that could be a guid or an actual name.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|||||||
@ -136,7 +136,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
winrt::hstring GetSerializationErrorMessage() const;
|
winrt::hstring GetSerializationErrorMessage() const;
|
||||||
|
|
||||||
// defterm
|
// defterm
|
||||||
static std::wstring NormalizeCommandLine(LPCWSTR commandLine);
|
|
||||||
static bool IsDefaultTerminalAvailable() noexcept;
|
static bool IsDefaultTerminalAvailable() noexcept;
|
||||||
static bool IsDefaultTerminalSet() noexcept;
|
static bool IsDefaultTerminalSet() noexcept;
|
||||||
winrt::Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() noexcept;
|
winrt::Windows::Foundation::Collections::IObservableVector<Model::DefaultTerminal> DefaultTerminals() noexcept;
|
||||||
|
|||||||
@ -606,7 +606,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
|
|
||||||
// - Escape the profile name for JSON appropriately
|
// - Escape the profile name for JSON appropriately
|
||||||
auto escapedProfileName = _escapeForJson(til::u16u8(p.Name()));
|
auto escapedProfileName = _escapeForJson(til::u16u8(p.Name()));
|
||||||
auto escapedProfileIcon = _escapeForJson(til::u16u8(p.Icon()));
|
auto escapedProfileIcon = _escapeForJson(til::u16u8(p.EvaluatedIcon()));
|
||||||
auto newJsonString = til::replace_needle_in_haystack(oldJsonString,
|
auto newJsonString = til::replace_needle_in_haystack(oldJsonString,
|
||||||
ProfileNameToken,
|
ProfileNameToken,
|
||||||
escapedProfileName);
|
escapedProfileName);
|
||||||
|
|||||||
@ -85,7 +85,6 @@ Author(s):
|
|||||||
X(hstring, StartingDirectory, "startingDirectory") \
|
X(hstring, StartingDirectory, "startingDirectory") \
|
||||||
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
|
X(bool, SuppressApplicationTitle, "suppressApplicationTitle", false) \
|
||||||
X(guid, ConnectionType, "connectionType") \
|
X(guid, ConnectionType, "connectionType") \
|
||||||
X(hstring, Icon, "icon", L"\uE756") \
|
|
||||||
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Automatic) \
|
X(CloseOnExitMode, CloseOnExit, "closeOnExit", CloseOnExitMode::Automatic) \
|
||||||
X(hstring, TabTitle, "tabTitle") \
|
X(hstring, TabTitle, "tabTitle") \
|
||||||
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
X(Model::BellStyle, BellStyle, "bellStyle", BellStyle::Audible) \
|
||||||
|
|||||||
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include "Profile.g.cpp"
|
#include "Profile.g.cpp"
|
||||||
|
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
using namespace Microsoft::Terminal::Settings::Model;
|
using namespace Microsoft::Terminal::Settings::Model;
|
||||||
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
|
||||||
using namespace winrt::Microsoft::Terminal::Control;
|
using namespace winrt::Microsoft::Terminal::Control;
|
||||||
@ -25,6 +27,7 @@ static constexpr std::string_view NameKey{ "name" };
|
|||||||
static constexpr std::string_view GuidKey{ "guid" };
|
static constexpr std::string_view GuidKey{ "guid" };
|
||||||
static constexpr std::string_view SourceKey{ "source" };
|
static constexpr std::string_view SourceKey{ "source" };
|
||||||
static constexpr std::string_view HiddenKey{ "hidden" };
|
static constexpr std::string_view HiddenKey{ "hidden" };
|
||||||
|
static constexpr std::string_view IconKey{ "icon" };
|
||||||
|
|
||||||
static constexpr std::string_view FontInfoKey{ "font" };
|
static constexpr std::string_view FontInfoKey{ "font" };
|
||||||
static constexpr std::string_view PaddingKey{ "padding" };
|
static constexpr std::string_view PaddingKey{ "padding" };
|
||||||
@ -104,6 +107,7 @@ winrt::com_ptr<Profile> Profile::CopySettings() const
|
|||||||
profile->_Hidden = _Hidden;
|
profile->_Hidden = _Hidden;
|
||||||
profile->_TabColor = _TabColor;
|
profile->_TabColor = _TabColor;
|
||||||
profile->_Padding = _Padding;
|
profile->_Padding = _Padding;
|
||||||
|
profile->_Icon = _Icon;
|
||||||
|
|
||||||
profile->_Origin = _Origin;
|
profile->_Origin = _Origin;
|
||||||
profile->_FontInfo = *fontInfo;
|
profile->_FontInfo = *fontInfo;
|
||||||
@ -170,6 +174,7 @@ void Profile::LayerJson(const Json::Value& json)
|
|||||||
JsonUtils::GetValueForKey(json, GuidKey, _Guid);
|
JsonUtils::GetValueForKey(json, GuidKey, _Guid);
|
||||||
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
JsonUtils::GetValueForKey(json, HiddenKey, _Hidden);
|
||||||
JsonUtils::GetValueForKey(json, SourceKey, _Source);
|
JsonUtils::GetValueForKey(json, SourceKey, _Source);
|
||||||
|
JsonUtils::GetValueForKey(json, IconKey, _Icon);
|
||||||
|
|
||||||
// Padding was never specified as an integer, but it was a common working mistake.
|
// Padding was never specified as an integer, but it was a common working mistake.
|
||||||
// Allow it to be permissive.
|
// Allow it to be permissive.
|
||||||
@ -312,6 +317,7 @@ Json::Value Profile::ToJson() const
|
|||||||
JsonUtils::SetValueForKey(json, GuidKey, writeBasicSettings ? Guid() : _Guid);
|
JsonUtils::SetValueForKey(json, GuidKey, writeBasicSettings ? Guid() : _Guid);
|
||||||
JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden);
|
JsonUtils::SetValueForKey(json, HiddenKey, writeBasicSettings ? Hidden() : _Hidden);
|
||||||
JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source);
|
JsonUtils::SetValueForKey(json, SourceKey, writeBasicSettings ? Source() : _Source);
|
||||||
|
JsonUtils::SetValueForKey(json, IconKey, writeBasicSettings ? Icon() : _Icon);
|
||||||
|
|
||||||
// PermissiveStringConverter is unnecessary for serialization
|
// PermissiveStringConverter is unnecessary for serialization
|
||||||
JsonUtils::SetValueForKey(json, PaddingKey, _Padding);
|
JsonUtils::SetValueForKey(json, PaddingKey, _Padding);
|
||||||
@ -336,3 +342,167 @@ Json::Value Profile::ToJson() const
|
|||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is the implementation for and INHERITABLE_SETTING, but with one addition
|
||||||
|
// in the setter. We want to make sure to clear out our cached icon, so that we
|
||||||
|
// can re-evaluate it as it changes in the SUI.
|
||||||
|
void Profile::Icon(const winrt::hstring& value)
|
||||||
|
{
|
||||||
|
_evaluatedIcon = std::nullopt;
|
||||||
|
_Icon = value;
|
||||||
|
}
|
||||||
|
winrt::hstring Profile::Icon() const
|
||||||
|
{
|
||||||
|
const auto val{ _getIconImpl() };
|
||||||
|
return val ? *val : hstring{ L"\uE756" };
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::hstring Profile::EvaluatedIcon()
|
||||||
|
{
|
||||||
|
// We cache the result here, so we don't search the path for the exe every time.
|
||||||
|
if (!_evaluatedIcon.has_value())
|
||||||
|
{
|
||||||
|
_evaluatedIcon = _evaluateIcon();
|
||||||
|
}
|
||||||
|
return *_evaluatedIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::hstring Profile::_evaluateIcon() const
|
||||||
|
{
|
||||||
|
// If the profile has an icon, return it.
|
||||||
|
if (!Icon().empty())
|
||||||
|
{
|
||||||
|
return Icon();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, use NormalizeCommandLine to find the actual exe name. This
|
||||||
|
// will actually search for the exe, including spaces, in the same way that
|
||||||
|
// CreateProcess does.
|
||||||
|
std::wstring cmdline{ NormalizeCommandLine(Commandline().c_str()) };
|
||||||
|
// NormalizeCommandLine will return a string with embedded nulls after each
|
||||||
|
// arg. We just want the first one.
|
||||||
|
return winrt::hstring{ cmdline.c_str() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a commandLine like the following:
|
||||||
|
// * "C:\WINDOWS\System32\cmd.exe"
|
||||||
|
// * "pwsh -WorkingDirectory ~"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe -WorkingDirectory ~"
|
||||||
|
//
|
||||||
|
// This function returns:
|
||||||
|
// * "C:\Windows\System32\cmd.exe"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe\0-WorkingDirectory\0~"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe\0-WorkingDirectory\0~"
|
||||||
|
//
|
||||||
|
// The resulting strings are then used for comparisons in _getProfileForCommandLine().
|
||||||
|
// For instance a resulting string of
|
||||||
|
// "C:\Program Files\PowerShell\7\pwsh.exe"
|
||||||
|
// is considered a compatible profile with
|
||||||
|
// "C:\Program Files\PowerShell\7\pwsh.exe -WorkingDirectory ~"
|
||||||
|
// as it shares the same (normalized) prefix.
|
||||||
|
std::wstring Profile::NormalizeCommandLine(LPCWSTR commandLine)
|
||||||
|
{
|
||||||
|
// Turn "%SystemRoot%\System32\cmd.exe" into "C:\WINDOWS\System32\cmd.exe".
|
||||||
|
// We do this early, as environment variables might occur anywhere in the commandLine.
|
||||||
|
std::wstring normalized;
|
||||||
|
THROW_IF_FAILED(wil::ExpandEnvironmentStringsW(commandLine, normalized));
|
||||||
|
|
||||||
|
// One of the most important things this function does is to strip quotes.
|
||||||
|
// That way the commandLine "foo.exe -bar" and "\"foo.exe\" \"-bar\"" appear identical.
|
||||||
|
// We'll abuse CommandLineToArgvW for that as it's close to what CreateProcessW uses.
|
||||||
|
auto argc = 0;
|
||||||
|
wil::unique_hlocal_ptr<PWSTR[]> argv{ CommandLineToArgvW(normalized.c_str(), &argc) };
|
||||||
|
THROW_LAST_ERROR_IF(!argc);
|
||||||
|
|
||||||
|
// The index of the first argument in argv for our executable in argv[0].
|
||||||
|
// Given {"C:\Program Files\PowerShell\7\pwsh.exe", "-WorkingDirectory", "~"} this will be 1.
|
||||||
|
auto startOfArguments = 1;
|
||||||
|
|
||||||
|
// The given commandLine should start with an executable name or path.
|
||||||
|
// For instance given the following argv arrays:
|
||||||
|
// * {"C:\WINDOWS\System32\cmd.exe"}
|
||||||
|
// * {"pwsh", "-WorkingDirectory", "~"}
|
||||||
|
// * {"C:\Program", "Files\PowerShell\7\pwsh.exe"}
|
||||||
|
// ^^^^
|
||||||
|
// Notice how there used to be a space in the path, which was split by ExpandEnvironmentStringsW().
|
||||||
|
// CreateProcessW() supports such atrocities, so we got to do the same.
|
||||||
|
// * {"C:\Program Files\PowerShell\7\pwsh.exe", "-WorkingDirectory", "~"}
|
||||||
|
//
|
||||||
|
// This loop tries to resolve relative paths, as well as executable names in %PATH%
|
||||||
|
// into absolute paths and normalizes them. The results for the above would be:
|
||||||
|
// * "C:\Windows\System32\cmd.exe"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
||||||
|
// * "C:\Program Files\PowerShell\7\pwsh.exe"
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// CreateProcessW uses RtlGetExePath to get the lpPath for SearchPathW.
|
||||||
|
// The difference between the behavior of SearchPathW if lpPath is nullptr and what RtlGetExePath returns
|
||||||
|
// seems to be mostly whether SafeProcessSearchMode is respected and the support for relative paths.
|
||||||
|
// Windows Terminal makes the use of relative paths rather impractical which is why we simply dropped the call to RtlGetExePath.
|
||||||
|
const auto status = wil::SearchPathW(nullptr, argv[0], L".exe", normalized);
|
||||||
|
|
||||||
|
if (status == S_OK)
|
||||||
|
{
|
||||||
|
const auto attributes = GetFileAttributesW(normalized.c_str());
|
||||||
|
|
||||||
|
if (attributes != INVALID_FILE_ATTRIBUTES && WI_IsFlagClear(attributes, FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
{
|
||||||
|
std::filesystem::path path{ std::move(normalized) };
|
||||||
|
|
||||||
|
// canonical() will resolve symlinks, etc. for us.
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
auto canonicalPath = std::filesystem::canonical(path, ec);
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
path = std::move(canonicalPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::filesystem::path has no way to extract the internal path.
|
||||||
|
// So about that.... I own you, computer. Give me that path.
|
||||||
|
normalized = std::move(const_cast<std::wstring&>(path.native()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All other error types aren't handled at the moment.
|
||||||
|
else if (status != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If the file path couldn't be found by SearchPathW this could be the result of us being given a commandLine
|
||||||
|
// like "C:\foo bar\baz.exe -arg" which is resolved to the argv array {"C:\foo", "bar\baz.exe", "-arg"},
|
||||||
|
// or we were erroneously given a directory to execute (e.g. someone ran `wt .`).
|
||||||
|
// Just like CreateProcessW() we thus try to concatenate arguments until we successfully resolve a valid path.
|
||||||
|
// Of course we can only do that if we have at least 2 remaining arguments in argv.
|
||||||
|
if ((argc - startOfArguments) < 2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As described in the comment right above, we concatenate arguments in an attempt to resolve a valid path.
|
||||||
|
// The code below turns argv from {"C:\foo", "bar\baz.exe", "-arg"} into {"C:\foo bar\baz.exe", "-arg"}.
|
||||||
|
// The code abuses the fact that CommandLineToArgvW allocates all arguments back-to-back on the heap separated by '\0'.
|
||||||
|
argv[startOfArguments][-1] = L' ';
|
||||||
|
++startOfArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've (hopefully) finished resolving the path to the executable.
|
||||||
|
// We're now going to append all remaining arguments to the resulting string.
|
||||||
|
// If argv is {"C:\Program Files\PowerShell\7\pwsh.exe", "-WorkingDirectory", "~"},
|
||||||
|
// then we'll get "C:\Program Files\PowerShell\7\pwsh.exe\0-WorkingDirectory\0~"
|
||||||
|
if (startOfArguments < argc)
|
||||||
|
{
|
||||||
|
// normalized contains a canonical form of argv[0] at this point.
|
||||||
|
// -1 allows us to include the \0 between argv[0] and argv[1] in the call to append().
|
||||||
|
const auto beg = argv[startOfArguments] - 1;
|
||||||
|
const auto lastArg = argv[argc - 1];
|
||||||
|
const auto end = lastArg + wcslen(lastArg);
|
||||||
|
normalized.append(beg, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|||||||
@ -102,9 +102,16 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
Model::IAppearanceConfig DefaultAppearance();
|
Model::IAppearanceConfig DefaultAppearance();
|
||||||
Model::FontConfig FontInfo();
|
Model::FontConfig FontInfo();
|
||||||
|
|
||||||
|
winrt::hstring EvaluatedIcon();
|
||||||
|
|
||||||
|
static std::wstring NormalizeCommandLine(LPCWSTR commandLine);
|
||||||
|
|
||||||
void _FinalizeInheritance() override;
|
void _FinalizeInheritance() override;
|
||||||
|
|
||||||
// Special fields
|
// Special fields
|
||||||
|
hstring Icon() const;
|
||||||
|
void Icon(const hstring& value);
|
||||||
|
|
||||||
WINRT_PROPERTY(bool, Deleted, false);
|
WINRT_PROPERTY(bool, Deleted, false);
|
||||||
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
|
WINRT_PROPERTY(OriginTag, Origin, OriginTag::None);
|
||||||
WINRT_PROPERTY(guid, Updates);
|
WINRT_PROPERTY(guid, Updates);
|
||||||
@ -119,7 +126,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
INHERITABLE_SETTING(Model::Profile, bool, Hidden, false);
|
INHERITABLE_SETTING(Model::Profile, bool, Hidden, false);
|
||||||
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
|
INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source()));
|
||||||
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
|
INHERITABLE_SETTING(Model::Profile, hstring, Padding, DEFAULT_PADDING);
|
||||||
|
// Icon is _very special_ because we want to customize its setter
|
||||||
|
_BASE_INHERITABLE_SETTING(Model::Profile, std::optional<hstring>, Icon, L"\uE756");
|
||||||
|
|
||||||
|
public:
|
||||||
#define PROFILE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
#define PROFILE_SETTINGS_INITIALIZE(type, name, jsonKey, ...) \
|
||||||
INHERITABLE_SETTING(Model::Profile, type, name, ##__VA_ARGS__)
|
INHERITABLE_SETTING(Model::Profile, type, name, ##__VA_ARGS__)
|
||||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_INITIALIZE)
|
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_INITIALIZE)
|
||||||
@ -128,10 +138,15 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
|||||||
private:
|
private:
|
||||||
Model::IAppearanceConfig _DefaultAppearance{ winrt::make<AppearanceConfig>(weak_ref<Model::Profile>(*this)) };
|
Model::IAppearanceConfig _DefaultAppearance{ winrt::make<AppearanceConfig>(weak_ref<Model::Profile>(*this)) };
|
||||||
Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) };
|
Model::FontConfig _FontInfo{ winrt::make<FontConfig>(weak_ref<Model::Profile>(*this)) };
|
||||||
|
|
||||||
|
std::optional<winrt::hstring> _evaluatedIcon{ std::nullopt };
|
||||||
|
|
||||||
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
|
static std::wstring EvaluateStartingDirectory(const std::wstring& directory);
|
||||||
|
|
||||||
static guid _GenerateGuidForProfile(const std::wstring_view& name, const std::wstring_view& source) noexcept;
|
static guid _GenerateGuidForProfile(const std::wstring_view& name, const std::wstring_view& source) noexcept;
|
||||||
|
|
||||||
|
winrt::hstring _evaluateIcon() const;
|
||||||
|
|
||||||
friend class SettingsModelLocalTests::DeserializationTests;
|
friend class SettingsModelLocalTests::DeserializationTests;
|
||||||
friend class SettingsModelLocalTests::ProfileTests;
|
friend class SettingsModelLocalTests::ProfileTests;
|
||||||
friend class SettingsModelLocalTests::ColorSchemeTests;
|
friend class SettingsModelLocalTests::ColorSchemeTests;
|
||||||
|
|||||||
@ -53,6 +53,10 @@ namespace Microsoft.Terminal.Settings.Model
|
|||||||
Boolean Deleted { get; };
|
Boolean Deleted { get; };
|
||||||
OriginTag Origin { get; };
|
OriginTag Origin { get; };
|
||||||
|
|
||||||
|
// Helper for magically using a commandline for an icon for a profile
|
||||||
|
// without an explicit icon.
|
||||||
|
String EvaluatedIcon { get; };
|
||||||
|
|
||||||
INHERITABLE_PROFILE_SETTING(Guid, Guid);
|
INHERITABLE_PROFILE_SETTING(Guid, Guid);
|
||||||
INHERITABLE_PROFILE_SETTING(String, Name);
|
INHERITABLE_PROFILE_SETTING(String, Name);
|
||||||
INHERITABLE_PROFILE_SETTING(String, Source);
|
INHERITABLE_PROFILE_SETTING(String, Source);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user