diff --git a/.github/actions/spelling/allow/allow.txt b/.github/actions/spelling/allow/allow.txt index 21d67b24bf2..13e2e78ed3b 100644 --- a/.github/actions/spelling/allow/allow.txt +++ b/.github/actions/spelling/allow/allow.txt @@ -78,6 +78,8 @@ ok'd overlined pipeline postmodern +Powerline +powerline ptys qof qps diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.cpp b/src/cascadia/TerminalSettingsEditor/Appearances.cpp index d1d15c2a244..8a3c9f943a2 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.cpp +++ b/src/cascadia/TerminalSettingsEditor/Appearances.cpp @@ -20,6 +20,28 @@ using namespace winrt::Microsoft::Terminal::Settings::Model; namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { + bool Font::HasPowerlineCharacters() + { + if (!_hasPowerlineCharacters.has_value()) + { + try + { + winrt::com_ptr font; + THROW_IF_FAILED(_family->GetFont(0, font.put())); + BOOL exists{}; + // We're actually checking for the "Extended" PowerLine glyph set. + // They're more fun. + THROW_IF_FAILED(font->HasCharacter(0xE0B6, &exists)); + _hasPowerlineCharacters = (exists == TRUE); + } + catch (...) + { + _hasPowerlineCharacters = false; + } + } + return _hasPowerlineCharacters.value_or(false); + } + AppearanceViewModel::AppearanceViewModel(const Model::AppearanceConfig& appearance) : _appearance{ appearance } { @@ -288,25 +310,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation IInspectable Appearances::CurrentFontFace() const { - // look for the current font in our shown list of fonts const auto& appearanceVM{ Appearance() }; const auto appearanceFontFace{ appearanceVM.FontFace() }; - const auto& currentFontList{ ShowAllFonts() ? ProfileViewModel::CompleteFontList() : ProfileViewModel::MonospaceFontList() }; - IInspectable fallbackFont; - for (const auto& font : currentFontList) - { - if (font.LocalizedName() == appearanceFontFace) - { - return box_value(font); - } - else if (font.LocalizedName() == L"Cascadia Mono") - { - fallbackFont = box_value(font); - } - } - - // we couldn't find the desired font, set to "Cascadia Mono" since that ships by default - return fallbackFont; + return box_value(ProfileViewModel::FindFontWithLocalizedName(appearanceFontFace)); } void Appearances::FontFace_SelectionChanged(const IInspectable& /*sender*/, const SelectionChangedEventArgs& e) diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.h b/src/cascadia/TerminalSettingsEditor/Appearances.h index 6793fa74be9..bc34e62978c 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.h +++ b/src/cascadia/TerminalSettingsEditor/Appearances.h @@ -36,14 +36,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation struct Font : FontT { public: - Font(std::wstring name, std::wstring localizedName) : + Font(std::wstring name, std::wstring localizedName, IDWriteFontFamily* family) : _Name{ name }, - _LocalizedName{ localizedName } {}; + _LocalizedName{ localizedName } + { + _family.copy_from(family); + } hstring ToString() { return _LocalizedName; } + bool HasPowerlineCharacters(); WINRT_PROPERTY(hstring, Name); WINRT_PROPERTY(hstring, LocalizedName); + + private: + winrt::com_ptr _family; + std::optional _hasPowerlineCharacters; }; struct AppearanceViewModel : AppearanceViewModelT, ViewModelHelper diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.idl b/src/cascadia/TerminalSettingsEditor/Appearances.idl index 05c639b3b3b..55ff2be721d 100644 --- a/src/cascadia/TerminalSettingsEditor/Appearances.idl +++ b/src/cascadia/TerminalSettingsEditor/Appearances.idl @@ -19,6 +19,7 @@ namespace Microsoft.Terminal.Settings.Editor { String Name { get; }; String LocalizedName { get; }; + Boolean HasPowerlineCharacters { get; }; } runtimeclass AppearanceViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged diff --git a/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp b/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp index 0551fc06d42..2c33b1b0f4a 100644 --- a/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp +++ b/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp @@ -8,15 +8,20 @@ using namespace ::winrt::Microsoft::Terminal::TerminalConnection; using namespace ::winrt::Windows::Foundation; +static constexpr std::wstring_view PromptTextPlain{ L"C:\\> " }; +static constexpr std::wstring_view PromptTextPowerline{ L"\x1b[49;34m\xe0b6\x1b[1;97;44m C:\\ \x1b[m\x1b[46;34m\xe0b8\x1b[49;36m\xe0b8\x1b[m " }; + // clang-format off static constexpr std::wstring_view PreviewText{ + L"\x001b" + L"c" // Hard Reset (RIS); on separate lines to avoid becoming 0x01BC L"Windows Terminal\r\n" - L"C:\\> \x1b[93m" L"git\x1b[m diff \x1b[90m-w\x1b[m\r\n" + L"{0}\x1b[93m" L"git\x1b[m diff \x1b[90m-w\x1b[m\r\n" L"\x1b[1m" L"diff --git a/win b/win\x1b[m\r\n" L"\x1b[36m@@ -1 +1 @@\x1b[m\r\n" L"\x1b[31m- Windows Console\x1b[m\r\n" L"\x1b[32m+ Windows Terminal!\x1b[m\r\n" - L"C:\\> \x1b[93mWrite-Host \x1b[36m\"\xd83c\xdf2f!\"\x1b[1D\x1b[m" + L"{0}\x1b[93mWrite-Host \x1b[36m\"\xd83c\xdf2f!\"\x1b[1D\x1b[m" }; // clang-format on @@ -27,7 +32,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void PreviewConnection::Start() noexcept { // Send the preview text - _TerminalOutputHandlers(PreviewText); + _TerminalOutputHandlers(fmt::format(PreviewText, _displayPowerlineGlyphs ? PromptTextPowerline : PromptTextPlain)); } void PreviewConnection::Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/) noexcept @@ -45,4 +50,13 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void PreviewConnection::Close() noexcept { } + + void PreviewConnection::DisplayPowerlineGlyphs(bool d) noexcept + { + if (_displayPowerlineGlyphs != d) + { + _displayPowerlineGlyphs = d; + Start(); + } + } } diff --git a/src/cascadia/TerminalSettingsEditor/PreviewConnection.h b/src/cascadia/TerminalSettingsEditor/PreviewConnection.h index 1b8d980ad21..7958611ca5c 100644 --- a/src/cascadia/TerminalSettingsEditor/PreviewConnection.h +++ b/src/cascadia/TerminalSettingsEditor/PreviewConnection.h @@ -27,9 +27,14 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void Resize(uint32_t rows, uint32_t columns) noexcept; void Close() noexcept; + void DisplayPowerlineGlyphs(bool d) noexcept; + winrt::Microsoft::Terminal::TerminalConnection::ConnectionState State() const noexcept { return winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::Connected; } WINRT_CALLBACK(TerminalOutput, winrt::Microsoft::Terminal::TerminalConnection::TerminalOutputHandler); TYPED_EVENT(StateChanged, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection, IInspectable); + + private: + bool _displayPowerlineGlyphs{ false }; }; } diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp index 547813d255b..5f31f6be579 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp @@ -21,6 +21,8 @@ using namespace winrt::Microsoft::Terminal::Settings::Model; namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { + static Editor::Font _FontObjectForDWriteFont(IDWriteFontFamily* family); + Windows::Foundation::Collections::IObservableVector ProfileViewModel::_MonospaceFontList{ nullptr }; Windows::Foundation::Collections::IObservableVector ProfileViewModel::_FontList{ nullptr }; @@ -118,12 +120,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation com_ptr fontFamily; THROW_IF_FAILED(fontCollection->GetFontFamily(i, fontFamily.put())); - // get the font's localized names - com_ptr localizedFamilyNames; - THROW_IF_FAILED(fontFamily->GetFamilyNames(localizedFamilyNames.put())); - // construct a font entry for tracking - if (const auto fontEntry{ _GetFont(localizedFamilyNames) }) + if (const auto fontEntry{ _FontObjectForDWriteFont(fontFamily.get()) }) { // check if the font is monospaced try @@ -159,7 +157,32 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation } CATCH_LOG(); - Editor::Font ProfileViewModel::_GetFont(com_ptr localizedFamilyNames) + Editor::Font ProfileViewModel::FindFontWithLocalizedName(const winrt::hstring& name) noexcept + { + // look for the current font in our shown list of fonts + Editor::Font fallbackFont{ nullptr }; + try + { + const auto& currentFontList{ CompleteFontList() }; + for (const auto& font : currentFontList) + { + if (font.LocalizedName() == name) + { + return font; + } + else if (font.LocalizedName() == L"Cascadia Mono") + { + fallbackFont = font; + } + } + } + CATCH_LOG(); + + // we couldn't find the desired font, set to "Cascadia Mono" if we found that since it ships by default + return fallbackFont; + } + + static Editor::Font _FontObjectForDWriteFont(IDWriteFontFamily* family) { // used for the font's name as an identifier (i.e. text block's font family property) std::wstring nameID; @@ -169,6 +192,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation std::wstring localizedName; UINT32 localizedNameIndex; + // get the font's localized names + winrt::com_ptr localizedFamilyNames; + THROW_IF_FAILED(family->GetFamilyNames(localizedFamilyNames.put())); + // use our current locale to find the localized name auto exists{ FALSE }; HRESULT hr; @@ -211,7 +238,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation if (!nameID.empty() && !localizedName.empty()) { - return make(nameID, localizedName); + return make(nameID, localizedName, family); } return nullptr; } diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h index 386c4876a14..0946d9146ad 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.h @@ -34,6 +34,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation static void UpdateFontList() noexcept; static Windows::Foundation::Collections::IObservableVector CompleteFontList() noexcept { return _FontList; }; static Windows::Foundation::Collections::IObservableVector MonospaceFontList() noexcept { return _MonospaceFontList; }; + static Editor::Font FindFontWithLocalizedName(winrt::hstring const& name) noexcept; ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings); Model::TerminalSettings TermSettings() const; @@ -123,8 +124,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation static Windows::Foundation::Collections::IObservableVector _MonospaceFontList; static Windows::Foundation::Collections::IObservableVector _FontList; - static Editor::Font _GetFont(com_ptr localizedFamilyNames); - Model::CascadiaSettings _appSettings; Editor::AppearanceViewModel _unfocusedAppearanceViewModel; }; diff --git a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl index f4dd21b9c7a..ab0bcbf2ffb 100644 --- a/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl +++ b/src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl @@ -36,6 +36,7 @@ namespace Microsoft.Terminal.Settings.Editor { static Windows.Foundation.Collections.IObservableVector CompleteFontList { get; }; static Windows.Foundation.Collections.IObservableVector MonospaceFontList { get; }; + static Font FindFontWithLocalizedName(String name); Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; }; diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp index 599b3eef513..d045bc3cf20 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp +++ b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp @@ -19,6 +19,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation Profiles_Appearance::Profiles_Appearance() { InitializeComponent(); + _previewConnection = winrt::make_self(); } void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e) @@ -36,7 +37,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation if (!_previewControl) { const auto settings = _Profile.TermSettings(); - _previewControl = Control::TermControl(settings, settings, make()); + _previewConnection->DisplayPowerlineGlyphs(_looksLikePowerlineFont()); + _previewControl = Control::TermControl(settings, settings, *_previewConnection); _previewControl.IsEnabled(false); _previewControl.AllowFocusWhenDisabled(false); _previewControl.DisplayCursorWhileBlurred(true); @@ -68,9 +70,25 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation _Profile.DeleteUnfocusedAppearance(); } + bool Profiles_Appearance::_looksLikePowerlineFont() const + { + if (_Profile && _Profile.DefaultAppearance()) + { + if (const auto fontName = _Profile.DefaultAppearance().FontFace(); !fontName.empty()) + { + if (const auto font = ProfileViewModel::FindFontWithLocalizedName(fontName)) + { + return font.HasPowerlineCharacters(); + } + } + } + return false; + } + void Profiles_Appearance::_onProfilePropertyChanged(const IInspectable&, const PropertyChangedEventArgs&) const { const auto settings = _Profile.TermSettings(); + _previewConnection->DisplayPowerlineGlyphs(_looksLikePowerlineFont()); _previewControl.UpdateControlSettings(settings, settings); } } diff --git a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h index 4e13f60c632..0eadfeb6a6e 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h +++ b/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.h @@ -5,6 +5,7 @@ #include "Profiles_Appearance.g.h" #include "Utils.h" +#include "PreviewConnection.h" namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { @@ -26,7 +27,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation private: void _onProfilePropertyChanged(const IInspectable&, const PropertyChangedEventArgs&) const; + bool _looksLikePowerlineFont() const; + winrt::com_ptr _previewConnection{ nullptr }; Microsoft::Terminal::Control::TermControl _previewControl{ nullptr }; Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker; Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _AppearanceViewModelChangedRevoker;