Merge branch 'dev/migrie/f/just-elevated-state-2' into dev/migrie/f/non-terminal-content-elevation-warning

This commit is contained in:
Mike Griese 2021-09-30 10:06:23 -05:00
commit ff333870fc
57 changed files with 1886 additions and 818 deletions

View file

@ -24,6 +24,7 @@ DTDs
DWINRT
enablewttlogging
Intelli
IVisual
LKG
LOCKFILE
Lxss

View file

@ -24,3 +24,4 @@ VERIFY_ARE_EQUAL\(L"[^"]+"
std::memory_order_[\w]+
D2DERR_SHADER_COMPILE_FAILED
TIL_FEATURE_[0-9A-Z_]+
vcvars\w*

File diff suppressed because it is too large Load diff

View file

@ -751,7 +751,7 @@ namespace TerminalAppLocalTests
});
VERIFY_SUCCEEDED(result);
Log::Comment(L"Move focus. This will cause us to un-zoom.");
Log::Comment(L"Move focus. We should still be zoomed.");
result = RunOnUIThread([&page]() {
// Set up action
MoveFocusArgs args{ FocusDirection::Left };
@ -761,7 +761,7 @@ namespace TerminalAppLocalTests
auto firstTab = page->_GetTerminalTabImpl(page->_tabs.GetAt(0));
VERIFY_ARE_EQUAL(2, firstTab->GetLeafPaneCount());
VERIFY_IS_FALSE(firstTab->IsZoomed());
VERIFY_IS_TRUE(firstTab->IsZoomed());
});
VERIFY_SUCCEEDED(result);
}
@ -1357,7 +1357,8 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
// And we should have stored a function to revert the change.
VERIFY_ARE_EQUAL(1u, page->_restorePreviewFuncs.size());
});
TestOnUIThread([&page]() {
@ -1383,7 +1384,8 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
// After preview there should be no more restore functions to execute.
VERIFY_ARE_EQUAL(0u, page->_restorePreviewFuncs.size());
});
}
@ -1428,7 +1430,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
});
TestOnUIThread([&page]() {
@ -1451,7 +1452,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be the same as it originally was");
VERIFY_ARE_EQUAL(til::color{ 0xff0c0c0c }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
});
}
@ -1498,7 +1498,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xff000000 }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
});
TestOnUIThread([&page]() {
@ -1522,7 +1521,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed to the preview");
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(originalSettings, page->_originalSettings);
});
TestOnUIThread([&page]() {
@ -1548,7 +1546,6 @@ namespace TerminalAppLocalTests
Log::Comment(L"Color should be changed");
VERIFY_ARE_EQUAL(til::color{ 0xffFAFAFA }, controlSettings.DefaultBackground());
VERIFY_ARE_EQUAL(nullptr, page->_originalSettings);
});
}

View file

@ -67,41 +67,17 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalPage::_EndPreviewColorScheme()
{
// Get the focused control
if (const auto& activeControl{ _GetActiveControl() })
for (const auto& f : _restorePreviewFuncs)
{
// Get the runtime settings of the focused control
const auto& controlSettings{ activeControl.Settings().as<TerminalSettings>() };
// Get the control's root settings, the ones that we actually
// assigned to it.
auto parentSettings{ controlSettings.GetParent() };
while (parentSettings.GetParent() != nullptr)
{
parentSettings = parentSettings.GetParent();
}
// If the root settings are the same as the ones we stashed,
// then reset the parent of the runtime settings to the stashed
// settings. This condition might be false if the settings
// hot-reloaded while the palette was open. In that case, we
// don't want to reset the settings to what they were _before_
// the hot-reload.
if (_originalSettings == parentSettings)
{
// Set the original settings as the parent of the control's settings
activeControl.Settings().as<TerminalSettings>().SetParent(_originalSettings);
}
activeControl.UpdateSettings();
f();
}
_originalSettings = nullptr;
_restorePreviewFuncs.clear();
}
// Method Description:
// - Preview handler for the SetColorScheme action.
// - This method will stash the settings of the current control in
// _originalSettings. Then it will create a new TerminalSettings object
// - This method will stash functions to reset the settings of the selected controls in
// _restorePreviewFuncs. Then it will create a new TerminalSettings object
// with only the properties from the ColorScheme set. It'll _insert_ a
// TerminalSettings between the control's root settings (built from
// CascadiaSettings) and the control's runtime settings. That'll cause the
@ -112,33 +88,63 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalPage::_PreviewColorScheme(const Settings::Model::SetColorSchemeArgs& args)
{
// Get the focused control
if (const auto& activeControl{ _GetActiveControl() })
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
{
if (const auto& scheme{ _settings.GlobalSettings().ColorSchemes().TryLookup(args.SchemeName()) })
{
// Clear the saved preview funcs because we don't need to add a restore each time
// the preview color changes, we only need to be able to restore the last one.
_restorePreviewFuncs.clear();
_ApplyToActiveControls([&](const auto& control) {
// Get the settings of the focused control and stash them
const auto& controlSettings = activeControl.Settings().as<TerminalSettings>();
const auto& controlSettings = control.Settings().as<TerminalSettings>();
// Make sure to recurse up to the root - if you're doing
// this while you're currently previewing a SetColorScheme
// action, then the parent of the control's settings is _the
// last preview TerminalSettings we inserted! We don't want
// to save that one!
_originalSettings = controlSettings.GetParent();
while (_originalSettings.GetParent() != nullptr)
auto originalSettings = controlSettings.GetParent();
while (originalSettings.GetParent() != nullptr)
{
_originalSettings = _originalSettings.GetParent();
originalSettings = originalSettings.GetParent();
}
// Create a new child for those settings
TerminalSettingsCreateResult fake{ _originalSettings };
TerminalSettingsCreateResult fake{ originalSettings };
const auto& childStruct = TerminalSettings::CreateWithParent(fake);
// Modify the child to have the applied color scheme
childStruct.DefaultSettings().ApplyColorScheme(scheme);
// Insert that new child as the parent of the control's settings
controlSettings.SetParent(childStruct.DefaultSettings());
activeControl.UpdateSettings();
}
control.UpdateSettings();
// Take a copy of the inputs, since they are pointers anyways.
_restorePreviewFuncs.emplace_back([=]() {
// Get the runtime settings of the focused control
const auto& controlSettings{ control.Settings().as<TerminalSettings>() };
// Get the control's root settings, the ones that we actually
// assigned to it.
auto parentSettings{ controlSettings.GetParent() };
while (parentSettings.GetParent() != nullptr)
{
parentSettings = parentSettings.GetParent();
}
// If the root settings are the same as the ones we stashed,
// then reset the parent of the runtime settings to the stashed
// settings. This condition might be false if the settings
// hot-reloaded while the palette was open. In that case, we
// don't want to reset the settings to what they were _before_
// the hot-reload.
if (originalSettings == parentSettings)
{
// Set the original settings as the parent of the control's settings
control.Settings().as<TerminalSettings>().SetParent(originalSettings);
}
control.UpdateSettings();
});
});
}
}

View file

@ -377,11 +377,10 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<AdjustFontSizeArgs>())
{
if (const auto& termControl{ _GetActiveControl() })
{
termControl.AdjustFontSize(realArgs.Delta());
args.Handled(true);
}
const auto res = _ApplyToActiveControls([&](auto& control) {
control.AdjustFontSize(realArgs.Delta());
});
args.Handled(res);
}
}
@ -395,21 +394,19 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleResetFontSize(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& termControl{ _GetActiveControl() })
{
termControl.ResetFontSize();
args.Handled(true);
}
const auto res = _ApplyToActiveControls([](auto& control) {
control.ResetFontSize();
});
args.Handled(res);
}
void TerminalPage::_HandleToggleShaderEffects(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& termControl{ _GetActiveControl() })
{
termControl.ToggleShaderEffects();
args.Handled(true);
}
const auto res = _ApplyToActiveControls([](auto& control) {
control.ToggleShaderEffects();
});
args.Handled(res);
}
void TerminalPage::_HandleToggleFocusMode(const IInspectable& /*sender*/,
@ -452,37 +449,33 @@ namespace winrt::TerminalApp::implementation
args.Handled(false);
if (const auto& realArgs = args.ActionArgs().try_as<SetColorSchemeArgs>())
{
if (const auto activeTab{ _GetFocusedTabImpl() })
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
{
if (auto activeControl = activeTab->GetActiveTerminalControl())
{
if (const auto scheme = _settings.GlobalSettings().ColorSchemes().TryLookup(realArgs.SchemeName()))
const auto res = _ApplyToActiveControls([&](auto& control) {
// Start by getting the current settings of the control
auto controlSettings = control.Settings().as<TerminalSettings>();
auto parentSettings = controlSettings;
// Those are the _runtime_ settings however. What we
// need to do is:
//
// 1. Blow away any colors set in the runtime settings.
// 2. Apply the color scheme to the parent settings.
//
// 1 is important to make sure that the effects of
// something like `colortool` are cleared when setting
// the scheme.
if (controlSettings.GetParent() != nullptr)
{
// Start by getting the current settings of the control
auto controlSettings = activeControl.Settings().as<TerminalSettings>();
auto parentSettings = controlSettings;
// Those are the _runtime_ settings however. What we
// need to do is:
//
// 1. Blow away any colors set in the runtime settings.
// 2. Apply the color scheme to the parent settings.
//
// 1 is important to make sure that the effects of
// something like `colortool` are cleared when setting
// the scheme.
if (controlSettings.GetParent() != nullptr)
{
parentSettings = controlSettings.GetParent();
}
// ApplyColorScheme(nullptr) will clear the old color scheme.
controlSettings.ApplyColorScheme(nullptr);
parentSettings.ApplyColorScheme(scheme);
activeControl.UpdateSettings();
args.Handled(true);
parentSettings = controlSettings.GetParent();
}
}
// ApplyColorScheme(nullptr) will clear the old color scheme.
controlSettings.ApplyColorScheme(nullptr);
parentSettings.ApplyColorScheme(scheme);
control.UpdateSettings();
});
args.Handled(res);
}
}
}
@ -896,11 +889,10 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<ClearBufferArgs>())
{
if (const auto termControl{ _GetActiveControl() })
{
termControl.ClearBuffer(realArgs.Clear());
args.Handled(true);
}
const auto res = _ApplyToActiveControls([&](auto& control) {
control.ClearBuffer(realArgs.Clear());
});
args.Handled(res);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -40,7 +40,8 @@ enum class Borders : int
Top = 0x1,
Bottom = 0x2,
Left = 0x4,
Right = 0x8
Right = 0x8,
All = 0xF
};
DEFINE_ENUM_FLAG_OPERATORS(Borders);
@ -58,8 +59,15 @@ public:
const winrt::Windows::UI::Xaml::Controls::UserControl& control,
const bool lastFocused = false);
Pane(std::shared_ptr<Pane> first,
std::shared_ptr<Pane> second,
const SplitState splitType,
const float splitPosition,
const bool lastFocused = false);
std::shared_ptr<Pane> GetActivePane();
winrt::Windows::UI::Xaml::Controls::UserControl GetUserControl() const;
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl() const;
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
@ -145,25 +153,43 @@ public:
// - true if the predicate returned true on any pane.
template<typename F>
//requires std::predicate<F, std::shared_ptr<Pane>>
bool WalkTree(F f)
auto WalkTree(F f) -> decltype(f(shared_from_this()))
{
if (f(shared_from_this()))
{
return true;
}
using R = std::invoke_result_t<F, std::shared_ptr<Pane>>;
static constexpr auto IsVoid = std::is_void_v<R>;
if (!_IsLeaf())
if constexpr (IsVoid)
{
return _firstChild->WalkTree(f) || _secondChild->WalkTree(f);
f(shared_from_this());
if (!_IsLeaf())
{
_firstChild->WalkTree(f);
_secondChild->WalkTree(f);
}
}
else
{
if (f(shared_from_this()))
{
return true;
}
return false;
if (!_IsLeaf())
{
return _firstChild->WalkTree(f) || _secondChild->WalkTree(f);
}
return false;
}
}
void CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states);
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
using gotFocusArgs = winrt::delegate<std::shared_ptr<Pane>, winrt::Windows::UI::Xaml::FocusState>;
DECLARE_EVENT(GotFocus, _GotFocusHandlers, gotFocusArgs);
DECLARE_EVENT(LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DECLARE_EVENT(PaneRaiseBell, _PaneRaiseBellHandlers, winrt::Windows::Foundation::EventHandler<bool>);
DECLARE_EVENT(Detached, _PaneDetachedHandlers, winrt::delegate<std::shared_ptr<Pane>>);
@ -176,8 +202,10 @@ private:
struct LayoutSizeNode;
winrt::Windows::UI::Xaml::Controls::Grid _root{};
winrt::Windows::UI::Xaml::Controls::Border _border{};
winrt::Windows::UI::Xaml::Controls::Border _borderFirst{};
winrt::Windows::UI::Xaml::Controls::Border _borderSecond{};
winrt::Windows::UI::Xaml::Controls::UserControl _control{ nullptr };
winrt::Microsoft::Terminal::TerminalConnection::ConnectionState _connectionState{ winrt::Microsoft::Terminal::TerminalConnection::ConnectionState::NotConnected };
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_focusedBorderBrush;
static winrt::Windows::UI::Xaml::Media::SolidColorBrush s_unfocusedBorderBrush;
@ -188,6 +216,7 @@ private:
float _desiredSplitPosition;
std::optional<uint32_t> _id;
std::weak_ptr<Pane> _parentChildPath{};
bool _lastActive{ false };
winrt::Microsoft::Terminal::Settings::Model::Profile _profile{ nullptr };
@ -208,6 +237,7 @@ private:
bool _IsLeaf() const noexcept;
bool _HasFocusedChild() const noexcept;
void _SetupChildCloseHandlers();
bool _HasChild(const std::shared_ptr<Pane> child);
std::pair<std::shared_ptr<Pane>, std::shared_ptr<Pane>> _Split(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
@ -235,6 +265,7 @@ private:
void _CloseChild(const bool closeFirst, const bool isDetaching);
winrt::fire_and_forget _CloseChildRoutine(const bool closeFirst);
void _Focus();
void _FocusFirstChild();
void _ControlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _ControlWarningBellHandler(winrt::Windows::Foundation::IInspectable const& sender,

View file

@ -190,6 +190,9 @@
<data name="CloseWindowWarningTitle" xml:space="preserve">
<value>Do you want to close all tabs?</value>
</data>
<data name="MultiplePanes" xml:space="preserve">
<value>Multiple panes</value>
</data>
<data name="TabCloseSubMenu" xml:space="preserve">
<value>Close...</value>
</data>

View file

@ -748,31 +748,32 @@ namespace winrt::TerminalApp::implementation
{
_UnZoomIfNeeded();
auto pane = terminalTab->GetActivePane();
if (const auto pane{ terminalTab->GetActivePane() })
{
if (const auto control{ pane->GetTerminalControl() })
if (pane->ContainsReadOnly())
{
if (control.ReadOnly())
ContentDialogResult warningResult = co_await _ShowCloseReadOnlyDialog();
// If the user didn't explicitly click on close tab - leave
if (warningResult != ContentDialogResult::Primary)
{
ContentDialogResult warningResult = co_await _ShowCloseReadOnlyDialog();
// If the user didn't explicitly click on close tab - leave
if (warningResult != ContentDialogResult::Primary)
{
co_return;
}
// Clean read-only mode to prevent additional prompt if closing the pane triggers closing of a hosting tab
if (control.ReadOnly())
{
control.ToggleReadOnly();
}
co_return;
}
pane->Close();
// Clean read-only mode to prevent additional prompt if closing the pane triggers closing of a hosting tab
pane->WalkTree([](auto p) {
if (const auto control{ p->GetTerminalControl() })
{
if (control.ReadOnly())
{
control.ToggleReadOnly();
}
}
return false;
});
}
pane->Close();
}
}
else if (auto index{ _GetFocusedTabIndex() })

View file

@ -263,6 +263,26 @@ namespace winrt::TerminalApp::implementation
bool _SwapPane(const Microsoft::Terminal::Settings::Model::FocusDirection& direction);
bool _MovePane(const uint32_t tabIdx);
template<typename F>
bool _ApplyToActiveControls(F f)
{
if (const auto tab{ _GetFocusedTabImpl() })
{
if (const auto activePane = tab->GetActivePane())
{
activePane->WalkTree([&](auto p) {
if (const auto& control{ p->GetTerminalControl() })
{
f(control);
}
});
return true;
}
}
return false;
}
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
TerminalApp::TabBase _GetFocusedTab() const noexcept;
@ -366,7 +386,7 @@ namespace winrt::TerminalApp::implementation
void _EndPreviewColorScheme();
void _PreviewColorScheme(const Microsoft::Terminal::Settings::Model::SetColorSchemeArgs& args);
winrt::Microsoft::Terminal::Settings::Model::Command _lastPreviewedCommand{ nullptr };
winrt::Microsoft::Terminal::Settings::Model::TerminalSettings _originalSettings{ nullptr };
std::vector<std::function<void()>> _restorePreviewFuncs{};
HRESULT _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);

View file

@ -67,8 +67,11 @@ namespace winrt::TerminalApp::implementation
_rootPane->FocusPane(firstId);
_activePane = _rootPane->GetActivePane();
}
// Set the active control
_mruPanes.insert(_mruPanes.begin(), _activePane->Id().value());
// If the focused pane is a leaf, add it to the MRU panes
if (const auto id = _activePane->Id())
{
_mruPanes.insert(_mruPanes.begin(), id.value());
}
_Setup();
}
@ -180,8 +183,8 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Returns nullptr if no children of this tab were the last control to be
// focused, or the TermControl that _was_ the last control to be focused (if
// there was one).
// focused, the active control of the current pane, or the last active child control
// of the active pane if it is a parent.
// - This control might not currently be focused, if the tab itself is not
// currently focused.
// Arguments:
@ -193,7 +196,7 @@ namespace winrt::TerminalApp::implementation
{
if (_activePane)
{
return _activePane->GetTerminalControl();
return _activePane->GetLastFocusedTerminalControl();
}
return nullptr;
}
@ -390,6 +393,10 @@ namespace winrt::TerminalApp::implementation
{
return _runtimeTabText;
}
if (!_activePane->_IsLeaf())
{
return RS_(L"MultiplePanes");
}
const auto lastFocusedControl = GetActiveTerminalControl();
return lastFocusedControl ? lastFocusedControl.Title() : L"";
}
@ -517,19 +524,14 @@ namespace winrt::TerminalApp::implementation
// either the first or second child, but this will always return the
// original pane first.
auto [original, newPane] = _activePane->Split(splitType, splitSize, profile, control);
// The active pane has an id if it is a leaf
if (activePaneId)
{
original->Id(activePaneId.value());
newPane->Id(_nextPaneId);
++_nextPaneId;
}
else
{
original->Id(_nextPaneId);
++_nextPaneId;
newPane->Id(_nextPaneId);
++_nextPaneId;
}
newPane->Id(_nextPaneId);
++_nextPaneId;
_activePane = original;
// Add a event handlers to the new panes' GotFocus event. When the pane
@ -557,8 +559,8 @@ namespace winrt::TerminalApp::implementation
// - The removed pane, if the remove succeeded.
std::shared_ptr<Pane> TerminalTab::DetachPane()
{
// if we only have one pane, remove it entirely
// and close this tab
// if we only have one pane, or the focused pane is the root, remove it
// entirely and close this tab
if (_rootPane == _activePane)
{
return DetachRoot();
@ -633,16 +635,12 @@ namespace winrt::TerminalApp::implementation
// Add the new pane as an automatic split on the active pane.
auto first = _activePane->AttachPane(pane, SplitDirection::Automatic);
// under current assumptions this condition should always be true.
// This will be true if the original _activePane is a leaf pane.
// If it is a parent pane then we don't want to set an ID on it.
if (previousId)
{
first->Id(previousId.value());
}
else
{
first->Id(_nextPaneId);
++_nextPaneId;
}
// Update with event handlers on the new child.
_activePane = first;
@ -718,7 +716,10 @@ namespace winrt::TerminalApp::implementation
// throughout the entire tree.
if (const auto newFocus = _rootPane->NavigateDirection(_activePane, direction, _mruPanes))
{
// Mark that we want the active pane to changed
_changingActivePane = true;
const auto res = _rootPane->FocusPane(newFocus);
_changingActivePane = false;
if (_zoomedPane)
{
@ -741,11 +742,22 @@ namespace winrt::TerminalApp::implementation
// - true if two panes were swapped.
bool TerminalTab::SwapPane(const FocusDirection& direction)
{
// You cannot swap panes with the parent/child pane because of the
// circular reference.
if (direction == FocusDirection::Parent || direction == FocusDirection::Child)
{
return false;
}
// NOTE: This _must_ be called on the root pane, so that it can propagate
// throughout the entire tree.
if (auto neighbor = _rootPane->NavigateDirection(_activePane, direction, _mruPanes))
{
return _rootPane->SwapPanes(_activePane, neighbor);
// SwapPanes will refocus the terminal to make sure that it has focus
// even after moving.
_changingActivePane = true;
const auto res = _rootPane->SwapPanes(_activePane, neighbor);
_changingActivePane = false;
return res;
}
return false;
@ -753,7 +765,10 @@ namespace winrt::TerminalApp::implementation
bool TerminalTab::FocusPane(const uint32_t id)
{
return _rootPane->FocusPane(id);
_changingActivePane = true;
const auto res = _rootPane->FocusPane(id);
_changingActivePane = false;
return res;
}
// Method Description:
@ -1050,7 +1065,7 @@ namespace winrt::TerminalApp::implementation
auto weakThis{ get_weak() };
std::weak_ptr<Pane> weakPane{ pane };
auto gotFocusToken = pane->GotFocus([weakThis](std::shared_ptr<Pane> sender) {
auto gotFocusToken = pane->GotFocus([weakThis](std::shared_ptr<Pane> sender, WUX::FocusState focus) {
// Do nothing if the Tab's lifetime is expired or pane isn't new.
auto tab{ weakThis.get() };
@ -1058,8 +1073,20 @@ namespace winrt::TerminalApp::implementation
{
if (sender != tab->_activePane)
{
tab->_UpdateActivePane(sender);
tab->_RecalculateAndApplyTabColor();
auto senderIsChild = tab->_activePane->_HasChild(sender);
// Only move focus if we the program moved focus, or the
// user moved with their mouse. This is a problem because a
// pane isn't a control itself, and if we have the parent
// focused we are fine if the terminal control is focused,
// but we don't want to update the active pane.
if (!senderIsChild ||
(focus == WUX::FocusState::Programmatic && tab->_changingActivePane) ||
focus == WUX::FocusState::Pointer)
{
tab->_UpdateActivePane(sender);
tab->_RecalculateAndApplyTabColor();
}
}
tab->_focusState = WUX::FocusState::Programmatic;
// This tab has gained focus, remove the bell indicator if it is active
@ -1094,8 +1121,19 @@ namespace winrt::TerminalApp::implementation
tab->Content(tab->_rootPane->GetRootElement());
tab->ExitZoom();
}
if (auto pane = weakPane.lock())
{
// When a parent pane is selected, but one of its children
// close out under it we still need to update title/focus information
// but the GotFocus handler will rightly see that the _activePane
// did not actually change. Triggering
if (pane != tab->_activePane && !tab->_activePane->_IsLeaf())
{
co_await winrt::resume_foreground(tab->Content().Dispatcher());
tab->_UpdateActivePane(tab->_activePane);
}
for (auto i = tab->_mruPanes.begin(); i != tab->_mruPanes.end(); ++i)
{
if (*i == pane->Id())
@ -1313,16 +1351,13 @@ namespace winrt::TerminalApp::implementation
// - The tab's color, if any
std::optional<winrt::Windows::UI::Color> TerminalTab::GetTabColor()
{
const auto& termControl{ GetActiveTerminalControl() };
if (!termControl)
{
return std::nullopt;
}
const auto currControlColor{ termControl.TabColor() };
std::optional<winrt::Windows::UI::Color> controlTabColor;
if (currControlColor != nullptr)
if (const auto& control = GetActiveTerminalControl())
{
controlTabColor = currControlColor.Value();
if (const auto color = control.TabColor())
{
controlTabColor = color.Value();
}
}
// A Tab's color will be the result of layering a variety of sources,
@ -1435,7 +1470,16 @@ namespace winrt::TerminalApp::implementation
// TabViewItem().Background() only sets the color of the tab background
// when the TabViewItem is unselected. So we still need to set the other
// properties ourselves.
TabViewItem().Background(deselectedTabBrush);
//
// GH#11294: DESPITE the fact that there's a Background() API that we
// could just call like:
//
// TabViewItem().Background(deselectedTabBrush);
//
// We actually can't, because it will make the part of the tab that
// doesn't contain the text totally transparent to hit tests. So we
// actually _do_ still need to set TabViewItemHeaderBackground manually.
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackground"), deselectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundSelected"), selectedTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPointerOver"), hoverTabBrush);
TabViewItem().Resources().Insert(winrt::box_value(L"TabViewItemHeaderBackgroundPressed"), selectedTabBrush);
@ -1481,6 +1525,7 @@ namespace winrt::TerminalApp::implementation
void TerminalTab::_ClearTabBackgroundColor()
{
winrt::hstring keys[] = {
L"TabViewItemHeaderBackground",
L"TabViewItemHeaderBackgroundSelected",
L"TabViewItemHeaderBackgroundPointerOver",
L"TabViewItemHeaderForeground",
@ -1501,9 +1546,6 @@ namespace winrt::TerminalApp::implementation
}
}
// Clear out the Background.
TabViewItem().Background(nullptr);
_RefreshVisualState();
_colorCleared();
}
@ -1613,6 +1655,11 @@ namespace winrt::TerminalApp::implementation
void TerminalTab::EnterZoom()
{
// Clear the content first, because with parent focusing it is possible
// to zoom the root pane, but setting the content will not trigger the
// property changed event since it is the same and you would end up with
// an empty tab.
Content(nullptr);
_zoomedPane = _activePane;
_rootPane->Maximize(_zoomedPane);
// Update the tab header to show the magnifying glass
@ -1621,6 +1668,7 @@ namespace winrt::TerminalApp::implementation
}
void TerminalTab::ExitZoom()
{
Content(nullptr);
_rootPane->Restore(_zoomedPane);
_zoomedPane = nullptr;
// Update the tab header to hide the magnifying glass
@ -1635,13 +1683,34 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Toggle read-only mode on the active pane
// - If a parent pane is selected, this will ensure that all children have
// the same read-only status.
void TerminalTab::TogglePaneReadOnly()
{
auto control = GetActiveTerminalControl();
if (control)
{
control.ToggleReadOnly();
}
auto hasReadOnly = false;
auto allReadOnly = true;
_activePane->WalkTree([&](auto p) {
if (const auto& control{ p->GetTerminalControl() })
{
hasReadOnly |= control.ReadOnly();
allReadOnly &= control.ReadOnly();
}
});
_activePane->WalkTree([&](auto p) {
if (const auto& control{ p->GetTerminalControl() })
{
// If all controls have the same read only state then just toggle
if (allReadOnly || !hasReadOnly)
{
control.ToggleReadOnly();
}
// otherwise set to all read only.
else if (!control.ReadOnly())
{
control.ToggleReadOnly();
}
}
});
}
// Method Description:

View file

@ -140,6 +140,7 @@ namespace winrt::TerminalApp::implementation
bool _receivedKeyDown{ false };
bool _iconHidden{ false };
bool _changingActivePane{ false };
winrt::hstring _runtimeTabText{};
bool _inRename{ false };

View file

@ -274,10 +274,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_updateAntiAliasingMode(_renderEngine.get());
// GH#5098: Inform the engine of the opacity of the default text background.
if (_settings.UseAcrylic())
{
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity()));
}
// GH#11315: Always do this, even if they don't have acrylic on.
_renderEngine->SetDefaultTextBackgroundOpacity(::base::saturated_cast<float>(_settings.Opacity()));
THROW_IF_FAILED(_renderEngine->Enable());
@ -469,6 +467,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_renderEngine->ToggleShaderEffects();
}
// Always redraw after toggling effects. This way even if the control
// does not have focus it will update immediately.
_renderer->TriggerRedrawAll();
}
// Method Description:

View file

@ -459,7 +459,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// GH#5098: Inform the engine of the new opacity of the default text background.
_core.SetBackgroundOpacity(::base::saturated_cast<float>(appearance.Opacity()));
_core.SetBackgroundOpacity(appearance.Opacity());
}
else
{

View file

@ -72,13 +72,15 @@
two font lists causes a crash within the ComboBox code.
As a workaround, introduce two ComboBox controls and only display one at a time.
-->
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
<ComboBox x:Uid="Profile_FontFaceBox"
ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind SourceProfile.MonospaceFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(ShowAllFonts), Mode=OneWay}" />
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
<ComboBox x:Uid="Profile_FontFaceBox"
ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind SourceProfile.CompleteFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
@ -97,7 +99,8 @@
HasSettingValue="{x:Bind Appearance.HasFontSize, Mode=OneWay}"
SettingOverrideSource="{x:Bind Appearance.FontSizeOverrideSource, Mode=OneWay}"
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
<muxc:NumberBox AcceptsExpression="False"
<muxc:NumberBox x:Uid="Profile_FontSizeBox"
AcceptsExpression="False"
LargeChange="10"
Maximum="128"
Minimum="1"

View file

@ -166,12 +166,14 @@
<!-- Columns -->
<local:SettingContainer x:Uid="Globals_InitialCols"
Margin="0">
<muxc:NumberBox Style="{StaticResource LaunchSizeNumberBoxStyle}"
<muxc:NumberBox x:Uid="Globals_InitialColsBox"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind State.Settings.GlobalSettings.InitialCols, Mode=TwoWay}" />
</local:SettingContainer>
<!-- Rows -->
<local:SettingContainer x:Uid="Globals_InitialRows">
<muxc:NumberBox Style="{StaticResource LaunchSizeNumberBoxStyle}"
<muxc:NumberBox x:Uid="Globals_InitialRowsBox"
Style="{StaticResource LaunchSizeNumberBoxStyle}"
Value="{x:Bind State.Settings.GlobalSettings.InitialRows, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>

View file

@ -81,7 +81,8 @@
SettingOverrideSource="{x:Bind State.Profile.CommandlineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<TextBox IsSpellCheckEnabled="False"
<TextBox x:Uid="Profile_CommandlineBox"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Commandline, Mode=TwoWay}" />
<Button x:Uid="Profile_CommandlineBrowse"
@ -99,7 +100,8 @@
SettingOverrideSource="{x:Bind State.Profile.StartingDirectoryOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
<TextBox x:Uid="Profile_StartingDirectoryBox"
IsEnabled="{x:Bind State.Profile.UseCustomStartingDirectory, Mode=OneWay}"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.StartingDirectory, Mode=TwoWay}" />
@ -121,7 +123,8 @@
HasSettingValue="{x:Bind State.Profile.HasIcon, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.IconOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<TextBox FontFamily="Segoe UI, Segoe MDL2 Assets"
<TextBox x:Uid="Profile_IconBox"
FontFamily="Segoe UI, Segoe MDL2 Assets"
IsSpellCheckEnabled="False"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Icon, Mode=TwoWay}" />
@ -438,7 +441,8 @@
ClearSettingValue="{x:Bind State.Profile.ClearHistorySize}"
HasSettingValue="{x:Bind State.Profile.HasHistorySize, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.HistorySizeOverrideSource, Mode=OneWay}">
<muxc:NumberBox LargeChange="100"
<muxc:NumberBox x:Uid="Profile_HistorySizeBox"
LargeChange="100"
Minimum="0"
SmallChange="10"
Style="{StaticResource NumberBoxSettingStyle}"

View file

@ -291,6 +291,14 @@
<value>The number of rows displayed in the window upon first load. Measured in characters.</value>
<comment>A description for what the "rows" setting does. Presented near "Globals_InitialRows.Header".</comment>
</data>
<data name="Globals_InitialColsBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Initial Columns</value>
<comment>Name for a control to choose the number of columns in the terminal's text grid.</comment>
</data>
<data name="Globals_InitialRowsBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Initial Rows</value>
<comment>Name for a control to choose the number of rows in the terminal's text grid.</comment>
</data>
<data name="Globals_FirstWindowPreference.Header" xml:space="preserve">
<value>When Terminal starts</value>
<comment>Header for a control to select how the terminal should load its first window.</comment>
@ -496,7 +504,7 @@
<comment>A description for what the "acrylic opacity" setting does. Presented near "Profile_AcrylicOpacity.Header".</comment>
</data>
<data name="Profile_Opacity.Header" xml:space="preserve">
<value>Background Opacity</value>
<value>Background opacity</value>
<comment>Header for a control to determine the level of opacity for the background of the control. The user can choose to make the background of the app more or less opaque.</comment>
</data>
<data name="Profile_Opacity.HelpText" xml:space="preserve">
@ -655,6 +663,10 @@
<value>Command line</value>
<comment>Header for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.</comment>
</data>
<data name="Profile_CommandlineBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Command line</value>
<comment>Name for a control to determine commandline executable (i.e. a .exe file) to run when a terminal session of this profile is launched.</comment>
</data>
<data name="Profile_Commandline.HelpText" xml:space="preserve">
<value>Executable used in the profile.</value>
<comment>A description for what the "command line" setting does. Presented near "Profile_Commandline".</comment>
@ -703,6 +715,10 @@
<value>Font face</value>
<comment>Header for a control to select the font for text in the app.</comment>
</data>
<data name="Profile_FontFaceBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Font face</value>
<comment>Name for a control to select the font for text in the app.</comment>
</data>
<data name="Profile_FontFace.HelpText" xml:space="preserve">
<value>Name of the font face used in the profile.</value>
<comment>A description for what the "font face" setting does. Presented near "Profile_FontFace".</comment>
@ -711,6 +727,10 @@
<value>Font size</value>
<comment>Header for a control to determine the size of the text in the app.</comment>
</data>
<data name="Profile_FontSizeBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Font size</value>
<comment>Name for a control to determine the size of the text in the app.</comment>
</data>
<data name="Profile_FontSize.HelpText" xml:space="preserve">
<value>Size of the font in points.</value>
<comment>A description for what the "font size" setting does. Presented near "Profile_FontSize".</comment>
@ -739,6 +759,10 @@
<value>History size</value>
<comment>Header for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session.</comment>
</data>
<data name="Profile_HistorySizeBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>History size</value>
<comment>Name for a control to determine how many lines of text can be saved in a session. In terminals, the "history" is the output generated within your session.</comment>
</data>
<data name="Profile_HistorySize.HelpText" xml:space="preserve">
<value>The number of lines above the ones displayed in the window you can scroll back to.</value>
<comment>A description for what the "history size" setting does. Presented near "Profile_HistorySize".</comment>
@ -747,6 +771,10 @@
<value>Icon</value>
<comment>Header for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.</comment>
</data>
<data name="Profile_IconBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Icon</value>
<comment>Name for a control to determine what icon can be used to represent this profile. This is not necessarily a file path, but can be one.</comment>
</data>
<data name="Profile_Icon.HelpText" xml:space="preserve">
<value>Emoji or image file location of the icon used in the profile.</value>
<comment>A description for what the "icon" setting does. Presented near "Profile_Icon".</comment>
@ -791,6 +819,10 @@
<value>Starting directory</value>
<comment>Header for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
</data>
<data name="Profile_StartingDirectoryBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Starting directory</value>
<comment>Name for a control to determine the directory the session opens it at launch. This is on a text box that accepts folder paths.</comment>
</data>
<data name="Profile_StartingDirectory.HelpText" xml:space="preserve">
<value>The directory the profile starts in when it is loaded.</value>
<comment>A description for what the "starting directory" setting does. Presented near "Profile_StartingDirectory".</comment>
@ -1227,7 +1259,7 @@
<comment>Header for a control to how text is formatted</comment>
</data>
<data name="Appearance_IntenseTextStyle.Header" xml:space="preserve">
<value>Intense Text Style</value>
<value>Intense text style</value>
<comment>Header for a control to select how "intense" text is formatted (bold, bright, both or none)</comment>
</data>
<data name="Appearance_IntenseTextStyleNone.Content" xml:space="preserve">

View file

@ -298,6 +298,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
return RS_(L"MoveFocusPreviousInOrder");
case FocusDirection::First:
return RS_(L"MoveFocusFirstPane");
case FocusDirection::Parent:
return RS_(L"MoveFocusParentPane");
case FocusDirection::Child:
return RS_(L"MoveFocusChildPane");
}
return winrt::hstring{

View file

@ -38,7 +38,9 @@ namespace Microsoft.Terminal.Settings.Model
Previous,
PreviousInOrder,
NextInOrder,
First
First,
Parent,
Child
};
enum SplitDirection

View file

@ -1,36 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "BaseVisualStudioGenerator.h"
#include "DynamicProfileUtils.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void BaseVisualStudioGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
// There's no point in enumerating valid Visual Studio instances more than once,
// so cache them for use by both Visual Studio profile generators.
static const auto instances = VsSetupConfiguration::QueryInstances();
for (auto const& instance : instances)
{
try
{
if (!IsInstanceValid(instance))
{
continue;
}
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profiles.emplace_back(std::move(profile));
}
CATCH_LOG();
}
}

View file

@ -1,35 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- BaseVisualStudioGenerator
Abstract:
- Base generator for Visual Studio Developer shell profiles
Author(s):
- Charles Willis - October 2020
--*/
#pragma once
#include "IDynamicProfileGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class BaseVisualStudioGenerator : public IDynamicProfileGenerator
{
public:
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
protected:
virtual bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileIconPath() const = 0;
};
};

View file

@ -11,8 +11,7 @@
#include "AzureCloudShellGenerator.h"
#include "PowershellCoreProfileGenerator.h"
#include "VsDevCmdGenerator.h"
#include "VsDevShellGenerator.h"
#include "VisualStudioGenerator.h"
#include "WslDistroGenerator.h"
// The following files are generated at build time into the "Generated Files" directory.
@ -131,8 +130,7 @@ void SettingsLoader::GenerateProfiles()
_executeGenerator(PowershellCoreProfileGenerator{});
_executeGenerator(WslDistroGenerator{});
_executeGenerator(AzureCloudShellGenerator{});
_executeGenerator(VsDevCmdGenerator{});
_executeGenerator(VsDevShellGenerator{});
_executeGenerator(VisualStudioGenerator{});
}
// A new settings.json gets a special treatment:

View file

@ -101,7 +101,7 @@ namespace Microsoft::Terminal::Settings::Model::JsonUtils
{
public:
DeserializationError(const Json::Value& value) :
runtime_error(std::string("failed to deserialize ") + (value.isNull() ? "" : value.asCString())),
runtime_error(std::string("failed to deserialize ") + (value.isNull() ? "" : value.asString())),
jsonValue{ value } {}
void SetKey(std::string_view newKey)

View file

@ -14,7 +14,8 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="BaseVisualStudioGenerator.h" />
<ClInclude Include="VcDevCmdGenerator.h" />
<ClInclude Include="VisualStudioGenerator.h" />
<ClInclude Include="DefaultTerminal.h">
<DependentUpon>DefaultTerminal.idl</DependentUpon>
</ClInclude>
@ -84,7 +85,8 @@
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="BaseVisualStudioGenerator.cpp" />
<ClCompile Include="VcDevCmdGenerator.cpp" />
<ClCompile Include="VisualStudioGenerator.cpp" />
<ClCompile Include="DefaultTerminal.cpp">
<DependentUpon>DefaultTerminal.idl</DependentUpon>
</ClCompile>
@ -241,7 +243,6 @@
</ItemDefinitionGroup>
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@ -266,4 +267,4 @@
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
<Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
</Project>
</Project>

View file

@ -34,7 +34,7 @@
<ClCompile Include="IconPathConverter.cpp" />
<ClCompile Include="DefaultTerminal.cpp" />
<ClCompile Include="FileUtils.cpp" />
<ClCompile Include="BaseVisualStudioGenerator.cpp">
<ClCompile Include="VisualStudioGenerator.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
<ClCompile Include="VsDevCmdGenerator.cpp">
@ -46,6 +46,9 @@
<ClCompile Include="VsSetupConfiguration.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
<ClCompile Include="VcDevCmdGenerator.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@ -80,7 +83,7 @@
<ClInclude Include="DefaultTerminal.h" />
<ClInclude Include="FileUtils.h" />
<ClInclude Include="HashUtils.h" />
<ClInclude Include="BaseVisualStudioGenerator.h">
<ClInclude Include="VisualStudioGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="VsDevCmdGenerator.h">
@ -92,6 +95,9 @@
<ClInclude Include="VsSetupConfiguration.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="VcDevCmdGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Midl Include="ActionArgs.idl" />
@ -123,4 +129,4 @@
<UniqueIdentifier>{81a6314f-aa5b-4533-a499-13bc3a5c4af0}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View file

@ -258,6 +258,12 @@
<data name="MoveFocusFirstPane" xml:space="preserve">
<value>Move focus to the first pane</value>
</data>
<data name="MoveFocusParentPane" xml:space="preserve">
<value>Move focus to the parent pane</value>
</data>
<data name="MoveFocusChildPane" xml:space="preserve">
<value>Move focus to the child pane</value>
</data>
<data name="SwapPaneCommandKey" xml:space="preserve">
<value>Swap pane</value>
</data>
@ -427,7 +433,7 @@
<value>Break into the debugger</value>
</data>
<data name="OpenSettingsUICommandKey" xml:space="preserve">
<value>Open Settings...</value>
<value>Open settings...</value>
</data>
<data name="RenameWindowCommandKey" xml:space="preserve">
<value>Rename window to "{0}"</value>
@ -450,15 +456,15 @@
<comment>{0} will be replaced with a user-specified number</comment>
</data>
<data name="ClearAllCommandKey" xml:space="preserve">
<value>Clear Buffer</value>
<value>Clear buffer</value>
<comment>A command to clear the entirety of the Terminal output buffer</comment>
</data>
<data name="ClearViewportCommandKey" xml:space="preserve">
<value>Clear Viewport</value>
<value>Clear viewport</value>
<comment>A command to clear the active viewport of the Terminal</comment>
</data>
<data name="ClearScrollbackCommandKey" xml:space="preserve">
<value>Clear Scrollback</value>
<value>Clear scrollback</value>
<comment>A command to clear the part of the buffer above the viewport</comment>
</data>
<data name="InboxWindowsConsoleAuthor" xml:space="preserve">

View file

@ -202,15 +202,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
_IntenseIsBold = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bold);
_IntenseIsBright = WI_IsFlagSet(appearance.IntenseTextStyle(), Microsoft::Terminal::Settings::Model::IntenseStyle::Bright);
// If the user set an opacity, then just use that. Otherwise, change the
// default value based off of whether useAcrylic was set or not. If they
// want acrylic, then default to 50%. Otherwise, default to 100% (fully
// opaque)
_Opacity = appearance.HasOpacity() ?
appearance.Opacity() :
UseAcrylic() ?
.5 :
1.0;
_Opacity = appearance.Opacity();
}
// Method Description:

View file

@ -373,7 +373,7 @@ struct IntAsFloatPercentConversionTrait : ::Microsoft::Terminal::Settings::Model
// Possible FocusDirection values
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FocusDirection)
{
JSON_MAPPINGS(8) = {
JSON_MAPPINGS(10) = {
pair_type{ "left", ValueType::Left },
pair_type{ "right", ValueType::Right },
pair_type{ "up", ValueType::Up },
@ -382,6 +382,8 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FocusDirection)
pair_type{ "previousInOrder", ValueType::PreviousInOrder },
pair_type{ "nextInOrder", ValueType::NextInOrder },
pair_type{ "first", ValueType::First },
pair_type{ "parent", ValueType::Parent },
pair_type{ "child", ValueType::Child },
};
};

View file

@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VcDevCmdGenerator.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void VcDevCmdGenerator::GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
const std::filesystem::path root{ GetVcCmdScriptDirectory(instance) };
if (!std::filesystem::exists(root))
{
return;
}
// x64 environments only installed on 64-bit machines.
#ifdef _WIN64
const auto vcvars64 = root / L"vcvars64.bat";
if (std::filesystem::exists(vcvars64))
{
auto profile = CreateProfile(instance, L"x64", vcvars64, hidden);
profiles.emplace_back(std::move(profile));
// Only the VC environment for the matching architecture should be shown by default.
hidden = true;
}
const auto vcvarsamd64_x86 = root / L"vcvarsamd64_x86.bat";
if (std::filesystem::exists(vcvarsamd64_x86))
{
auto profile = CreateProfile(instance, L"x64_x86", vcvarsamd64_x86, true);
profiles.emplace_back(std::move(profile));
}
const auto vcvarsx86_amd64 = root / L"vcvarsx86_amd64.bat";
if (std::filesystem::exists(vcvarsx86_amd64))
{
auto profile = CreateProfile(instance, L"x86_x64", vcvarsx86_amd64, true);
profiles.emplace_back(std::move(profile));
}
#endif // _WIN64
const auto vcvars32 = root / L"vcvars32.bat";
if (std::filesystem::exists(vcvars32))
{
auto profile = CreateProfile(instance, L"x86", vcvars32, hidden);
profiles.emplace_back(std::move(profile));
}
}
CATCH_LOG();
}
winrt::com_ptr<implementation::Profile> VcDevCmdGenerator::CreateProfile(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix, const std::filesystem::path& path, bool hidden) const
{
const auto seed = GetProfileGuidSeed(instance, path);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance, prefix) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(path) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profile->Hidden(hidden);
return profile;
}
std::wstring VcDevCmdGenerator::GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance, const std::filesystem::path& path) const
{
return L"VsDevCmd" + instance.GetInstanceId() + path.native();
}
std::wstring VcDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix) const
{
std::wstring name{ prefix + L" Native Tools Command Prompt for VS " };
name.append(instance.GetProfileNameSuffix());
return name;
}
std::wstring VcDevCmdGenerator::GetProfileCommandLine(const std::filesystem::path& path) const
{
std::wstring commandLine{ L"cmd.exe /k \"" + path.native() + L"\"" };
return commandLine;
}
std::wstring VcDevCmdGenerator::GetVcCmdScriptDirectory(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return instance.ResolvePath(L"VC\\Auxiliary\\Build\\");
}

View file

@ -0,0 +1,40 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- VcDevCmdGenerator
Abstract:
- Dynamic profile generator for Visual C++ development environments.
Author(s):
- Heath Stewart - September 2021
--*/
#pragma once
#include "VisualStudioGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VcDevCmdGenerator final : public VisualStudioGenerator::IVisualStudioProfileGenerator
{
public:
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
private:
winrt::com_ptr<implementation::Profile> CreateProfile(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix, const std::filesystem::path& path, bool hidden) const;
std::wstring GetProfileIconPath() const
{
return L"ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png";
}
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance, const std::filesystem::path& path) const;
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix) const;
std::wstring GetProfileCommandLine(const std::filesystem::path& path) const;
std::wstring GetVcCmdScriptDirectory(const VsSetupConfiguration::VsSetupInstance& instance) const;
};
};

View file

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VisualStudioGenerator.h"
#include "VcDevCmdGenerator.h"
#include "VsDevCmdGenerator.h"
#include "VsDevShellGenerator.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring_view VisualStudioGenerator::GetNamespace() const noexcept
{
return std::wstring_view{ L"Windows.Terminal.VisualStudio" };
}
void VisualStudioGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
const auto instances = VsSetupConfiguration::QueryInstances();
VsDevCmdGenerator devCmdGenerator;
VcDevCmdGenerator vcCmdGenerator;
VsDevShellGenerator devShellGenerator;
// Instances are ordered from latest to oldest. Hide all but the profiles for the latest instance.
bool hidden = false;
for (auto const& instance : instances)
{
devCmdGenerator.GenerateProfiles(instance, hidden, profiles);
vcCmdGenerator.GenerateProfiles(instance, hidden, profiles);
devShellGenerator.GenerateProfiles(instance, hidden, profiles);
hidden = true;
}
}

View file

@ -0,0 +1,38 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- VisualStudioGenerator
Abstract:
- Generator for Visual Studio shell profiles. Actual profile generation is delegated
to separate classes that encapsulate different logic for cmd- and powershell-based shells,
as well as VC startup scripts specific to the current processor architecture.
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
#pragma once
#include "IDynamicProfileGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VisualStudioGenerator : public IDynamicProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override;
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
class IVisualStudioProfileGenerator
{
public:
virtual void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const = 0;
};
};
};

View file

@ -2,10 +2,33 @@
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VsDevCmdGenerator.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void VsDevCmdGenerator::GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
if (!IsInstanceValid(instance))
{
return;
}
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profile->Hidden(hidden);
profiles.emplace_back(std::move(profile));
}
CATCH_LOG();
}
std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{
std::wstring name{ L"Developer Command Prompt for VS " };
@ -15,7 +38,12 @@ std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSet
std::wstring VsDevCmdGenerator::GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const
{
std::wstring commandLine{ L"cmd.exe /k \"" + instance.GetDevCmdScriptPath() + L"\"" };
std::wstring commandLine{ L"cmd.exe /k \"" + GetDevCmdScriptPath(instance) + L"\"" };
return commandLine;
}
std::wstring VsDevCmdGenerator::GetDevCmdScriptPath(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return instance.ResolvePath(L"Common7\\Tools\\VsDevCmd.bat");
}

View file

@ -10,23 +10,23 @@ Abstract:
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
#pragma once
#include "BaseVisualStudioGenerator.h"
#include "VisualStudioGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VsDevCmdGenerator final : public BaseVisualStudioGenerator
class VsDevCmdGenerator final : public VisualStudioGenerator::IVisualStudioProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override
{
return std::wstring_view{ L"Windows.Terminal.VisualStudio.CommandPrompt" };
}
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance&) const override
private:
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance&) const
{
// We only support version of VS from 15.0.
// Per heaths: The [ISetupConfiguration] COM server only supports Visual Studio 15.0 and newer anyway.
@ -34,17 +34,18 @@ namespace winrt::Microsoft::Terminal::Settings::Model
return true;
}
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const override
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return L"VsDevCmd" + instance.GetInstanceId();
}
std::wstring GetProfileIconPath() const override
std::wstring GetProfileIconPath() const
{
return L"ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png";
}
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetDevCmdScriptPath(const VsSetupConfiguration::VsSetupInstance& instance) const;
};
};

View file

@ -2,11 +2,34 @@
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VsDevShellGenerator.h"
#include "VsSetupConfiguration.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void VsDevShellGenerator::GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
if (!IsInstanceValid(instance))
{
return;
}
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profile->Hidden(hidden);
profiles.emplace_back(std::move(profile));
}
CATCH_LOG();
}
std::wstring VsDevShellGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{
std::wstring name{ L"Developer PowerShell for VS " };
@ -20,9 +43,20 @@ std::wstring VsDevShellGenerator::GetProfileCommandLine(const VsSetupConfigurati
// The "SkipAutomaticLocation" parameter will prevent "Enter-VsDevShell" from automatically setting the shell path
// so the path in the profile will be used instead.
std::wstring commandLine{ L"powershell.exe -NoExit -Command \"& {" };
commandLine.append(L"Import-Module \"\"\"" + instance.GetDevShellModulePath() + L"\"\"\";");
commandLine.append(L"Import-Module \"\"\"" + GetDevShellModulePath(instance) + L"\"\"\";");
commandLine.append(L"Enter-VsDevShell " + instance.GetInstanceId() + L" -SkipAutomaticLocation");
commandLine.append(L"}\"");
return commandLine;
}
std::wstring VsDevShellGenerator::GetDevShellModulePath(const VsSetupConfiguration::VsSetupInstance& instance) const
{
// The path of Microsoft.VisualStudio.DevShell.dll changed in 16.3
if (instance.VersionInRange(L"[16.3,"))
{
return instance.ResolvePath(L"Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll");
}
return instance.ResolvePath(L"Common7\\Tools\\vsdevshell\\Microsoft.VisualStudio.DevShell.dll");
}

View file

@ -10,38 +10,39 @@ Abstract:
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
#pragma once
#include "BaseVisualStudioGenerator.h"
#include "VisualStudioGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VsDevShellGenerator final : public BaseVisualStudioGenerator
class VsDevShellGenerator final : public VisualStudioGenerator::IVisualStudioProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override
{
return std::wstring_view{ L"Windows.Terminal.VisualStudio.Powershell" };
}
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const override
private:
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return instance.VersionInRange(L"[16.2,)");
}
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const override
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return L"VsDevShell" + instance.GetInstanceId();
}
std::wstring GetProfileIconPath() const override
std::wstring GetProfileIconPath() const
{
return L"ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png";
}
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetDevShellModulePath(const VsSetupConfiguration::VsSetupInstance& instance) const;
};
};

View file

@ -32,6 +32,19 @@ std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryIn
THROW_IF_FAILED(result);
// Sort instances based on version and install date from latest to oldest.
std::sort(instances.begin(), instances.end(), [](const VsSetupInstance& a, const VsSetupInstance& b) {
auto const aVersion = a.GetComparableVersion();
auto const bVersion = b.GetComparableVersion();
if (aVersion == bVersion)
{
return a.GetComparableInstallDate() > b.GetComparableInstallDate();
}
return aVersion > bVersion;
});
return instances;
}
@ -95,6 +108,13 @@ std::wstring VsSetupConfiguration::GetInstanceId(ISetupInstance* pInst)
return bstrInstanceId.get();
}
unsigned long long VsSetupConfiguration::GetInstallDate(ISetupInstance* pInst)
{
FILETIME ftInstallDate{ 0 };
THROW_IF_FAILED(pInst->GetInstallDate(&ftInstallDate));
return wil::filetime::to_int64(ftInstallDate);
}
std::wstring VsSetupConfiguration::GetStringProperty(ISetupPropertyStore* pProps, std::wstring_view name)
{
if (pProps == nullptr)

View file

@ -10,6 +10,7 @@ Abstract:
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
@ -37,27 +38,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model
public:
struct VsSetupInstance
{
VsSetupInstance(VsSetupInstance&& other) = default;
VsSetupInstance& operator=(VsSetupInstance&&) = default;
std::wstring ResolvePath(std::wstring_view relativePath) const
{
return VsSetupConfiguration::ResolvePath(inst.get(), relativePath);
}
std::wstring GetDevShellModulePath() const
{
// The path of Microsoft.VisualStudio.DevShell.dll changed in 16.3
if (VersionInRange(L"[16.3,"))
{
return ResolvePath(L"Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll");
}
return ResolvePath(L"Common7\\Tools\\vsdevshell\\Microsoft.VisualStudio.DevShell.dll");
}
std::wstring GetDevCmdScriptPath() const
{
return ResolvePath(L"Common7\\Tools\\VsDevCmd.bat");
}
bool VersionInRange(std::wstring_view range) const
{
return InstallationVersionInRange(query.get(), inst.get(), range);
@ -65,7 +53,17 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring GetVersion() const
{
return GetInstallationVersion(inst.get());
return VsSetupConfiguration::GetInstallationVersion(inst.get());
}
unsigned long long GetComparableInstallDate() const
{
return installDate;
}
unsigned long long GetComparableVersion() const
{
return version;
}
std::wstring GetInstallationPath() const
@ -120,9 +118,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model
friend class VsSetupConfiguration;
VsSetupInstance(ComPtrSetupQuery pQuery, ComPtrSetupInstance pInstance) :
query(std::move(pQuery)),
inst(std::move(pInstance)),
profileNameSuffix(BuildProfileNameSuffix())
query(pQuery), // Copy and AddRef the query object.
inst(std::move(pInstance)), // Take ownership of the instance object.
profileNameSuffix(BuildProfileNameSuffix()),
installDate(GetInstallDate()),
version(GetInstallationVersion())
{
}
@ -131,6 +131,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring profileNameSuffix;
// Cache oft-accessed properties used in sorting.
unsigned long long installDate;
unsigned long long version;
std::wstring BuildProfileNameSuffix() const
{
ComPtrCatalogPropertyStore catalogProperties = GetCatalogPropertyStore();
@ -167,6 +171,22 @@ namespace winrt::Microsoft::Terminal::Settings::Model
return GetVersion();
}
unsigned long long GetInstallDate() const
{
return VsSetupConfiguration::GetInstallDate(inst.get());
}
unsigned long long GetInstallationVersion() const
{
const auto helper = wil::com_query<ISetupHelper>(query);
std::wstring versionString{ GetVersion() };
unsigned long long version{ 0 };
THROW_IF_FAILED(helper->ParseVersion(versionString.data(), &version));
return version;
}
static std::wstring GetChannelNameSuffixTag(ISetupPropertyStore* instanceProperties)
{
std::wstring tag;
@ -229,6 +249,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model
static std::wstring GetInstallationVersion(ISetupInstance* pInst);
static std::wstring GetInstallationPath(ISetupInstance* pInst);
static std::wstring GetInstanceId(ISetupInstance* pInst);
static unsigned long long GetInstallDate(ISetupInstance* pInst);
static std::wstring GetStringProperty(ISetupPropertyStore* pProps, std::wstring_view name);
};
};

View file

@ -354,6 +354,8 @@
{ "command": { "action": "moveFocus", "direction": "previousInOrder" } },
{ "command": { "action": "moveFocus", "direction": "nextInOrder" } },
{ "command": { "action": "moveFocus", "direction": "first" } },
{ "command": { "action": "moveFocus", "direction": "parent" } },
{ "command": { "action": "moveFocus", "direction": "child" } },
{ "command": { "action": "swapPane", "direction": "down" } },
{ "command": { "action": "swapPane", "direction": "left" } },
{ "command": { "action": "swapPane", "direction": "right" } },

View file

@ -166,7 +166,7 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid
CATCH_RETURN();
}
[[nodiscard]] HRESULT BgfxEngine::PaintBufferGridLines(GridLines const /*lines*/,
[[nodiscard]] HRESULT BgfxEngine::PaintBufferGridLines(GridLineSet const /*lines*/,
COLORREF const /*color*/,
size_t const /*cchLine*/,
COORD const /*coordTarget*/) noexcept

View file

@ -53,7 +53,7 @@ namespace Microsoft::Console::Render
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLines const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;

View file

@ -898,50 +898,50 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
// Arguments:
// - textAttribute: the TextAttribute to generate GridLines from.
// Return Value:
// - a GridLines containing all the gridline info from the TextAttribute
IRenderEngine::GridLines Renderer::s_GetGridlines(const TextAttribute& textAttribute) noexcept
// - a GridLineSet containing all the gridline info from the TextAttribute
IRenderEngine::GridLineSet Renderer::s_GetGridlines(const TextAttribute& textAttribute) noexcept
{
// Convert console grid line representations into rendering engine enum representations.
IRenderEngine::GridLines lines = IRenderEngine::GridLines::None;
IRenderEngine::GridLineSet lines;
if (textAttribute.IsTopHorizontalDisplayed())
{
lines |= IRenderEngine::GridLines::Top;
lines.set(IRenderEngine::GridLines::Top);
}
if (textAttribute.IsBottomHorizontalDisplayed())
{
lines |= IRenderEngine::GridLines::Bottom;
lines.set(IRenderEngine::GridLines::Bottom);
}
if (textAttribute.IsLeftVerticalDisplayed())
{
lines |= IRenderEngine::GridLines::Left;
lines.set(IRenderEngine::GridLines::Left);
}
if (textAttribute.IsRightVerticalDisplayed())
{
lines |= IRenderEngine::GridLines::Right;
lines.set(IRenderEngine::GridLines::Right);
}
if (textAttribute.IsCrossedOut())
{
lines |= IRenderEngine::GridLines::Strikethrough;
lines.set(IRenderEngine::GridLines::Strikethrough);
}
if (textAttribute.IsUnderlined())
{
lines |= IRenderEngine::GridLines::Underline;
lines.set(IRenderEngine::GridLines::Underline);
}
if (textAttribute.IsDoublyUnderlined())
{
lines |= IRenderEngine::GridLines::DoubleUnderline;
lines.set(IRenderEngine::GridLines::DoubleUnderline);
}
if (textAttribute.IsHyperlink())
{
lines |= IRenderEngine::GridLines::HyperlinkUnderline;
lines.set(IRenderEngine::GridLines::HyperlinkUnderline);
}
return lines;
}
@ -962,7 +962,7 @@ void Renderer::_PaintBufferOutputGridLineHelper(_In_ IRenderEngine* const pEngin
const COORD coordTarget)
{
// Convert console grid line representations into rendering engine enum representations.
IRenderEngine::GridLines lines = Renderer::s_GetGridlines(textAttribute);
auto lines = Renderer::s_GetGridlines(textAttribute);
// For now, we dash underline patterns and switch to regular underline on hover
// Since we're only rendering pattern links on *hover*, there's no point in checking
@ -975,13 +975,13 @@ void Renderer::_PaintBufferOutputGridLineHelper(_In_ IRenderEngine* const pEngin
{
if (_pData->GetPatternId(coordTarget).size() > 0)
{
lines |= IRenderEngine::GridLines::Underline;
lines.set(IRenderEngine::GridLines::Underline);
}
}
}
// Return early if there are no lines to paint.
if (lines != IRenderEngine::GridLines::None)
if (lines.any())
{
// Get the current foreground color to render the lines.
const COLORREF rgb = _pData->GetAttributeColors(textAttribute).first;

View file

@ -87,7 +87,7 @@ namespace Microsoft::Console::Render
void UpdateLastHoveredInterval(const std::optional<interval_tree::IntervalTree<til::point, size_t>::interval>& newInterval);
private:
static IRenderEngine::GridLines s_GetGridlines(const TextAttribute& textAttribute) noexcept;
static IRenderEngine::GridLineSet s_GetGridlines(const TextAttribute& textAttribute) noexcept;
static bool s_IsSoftFontChar(const std::wstring_view& v, const size_t firstSoftFontChar, const size_t lastSoftFontChar);
void _NotifyPaintFrame();

View file

@ -247,6 +247,7 @@ bool DxEngine::_HasTerminalEffects() const noexcept
void DxEngine::ToggleShaderEffects()
{
_terminalEffectsEnabled = !_terminalEffectsEnabled;
_recreateDeviceRequested = true;
LOG_IF_FAILED(InvalidateAll());
}
@ -1705,7 +1706,7 @@ CATCH_RETURN()
// - We will draw rightward (+X) from here
// Return Value:
// - S_OK or relevant DirectX error
[[nodiscard]] HRESULT DxEngine::PaintBufferGridLines(GridLines const lines,
[[nodiscard]] HRESULT DxEngine::PaintBufferGridLines(GridLineSet const lines,
COLORREF const color,
size_t const cchLine,
COORD const coordTarget) noexcept
@ -1732,13 +1733,13 @@ try
// offset by half the stroke width. For the start coordinate we add half
// the stroke width, and for the end coordinate we subtract half the width.
const DxFontRenderData::LineMetrics lineMetrics = _fontRenderData->GetLineMetrics();
if (WI_IsAnyFlagSet(lines, (GridLines::Left | GridLines::Right)))
if (lines.any(GridLines::Left, GridLines::Right))
{
const auto halfGridlineWidth = lineMetrics.gridlineWidth / 2.0f;
const auto startY = target.y + halfGridlineWidth;
const auto endY = target.y + font.height - halfGridlineWidth;
if (WI_IsFlagSet(lines, GridLines::Left))
if (lines.test(GridLines::Left))
{
auto x = target.x + halfGridlineWidth;
for (size_t i = 0; i < cchLine; i++, x += font.width)
@ -1747,7 +1748,7 @@ try
}
}
if (WI_IsFlagSet(lines, GridLines::Right))
if (lines.test(GridLines::Right))
{
auto x = target.x + font.width - halfGridlineWidth;
for (size_t i = 0; i < cchLine; i++, x += font.width)
@ -1757,19 +1758,19 @@ try
}
}
if (WI_IsAnyFlagSet(lines, GridLines::Top | GridLines::Bottom))
if (lines.any(GridLines::Top, GridLines::Bottom))
{
const auto halfGridlineWidth = lineMetrics.gridlineWidth / 2.0f;
const auto startX = target.x + halfGridlineWidth;
const auto endX = target.x + fullRunWidth - halfGridlineWidth;
if (WI_IsFlagSet(lines, GridLines::Top))
if (lines.test(GridLines::Top))
{
const auto y = target.y + halfGridlineWidth;
DrawLine(startX, y, endX, y, lineMetrics.gridlineWidth);
}
if (WI_IsFlagSet(lines, GridLines::Bottom))
if (lines.test(GridLines::Bottom))
{
const auto y = target.y + font.height - halfGridlineWidth;
DrawLine(startX, y, endX, y, lineMetrics.gridlineWidth);
@ -1779,24 +1780,24 @@ try
// In the case of the underline and strikethrough offsets, the stroke width
// is already accounted for, so they don't require further adjustments.
if (WI_IsAnyFlagSet(lines, GridLines::Underline | GridLines::DoubleUnderline | GridLines::HyperlinkUnderline))
if (lines.any(GridLines::Underline, GridLines::DoubleUnderline, GridLines::HyperlinkUnderline))
{
const auto halfUnderlineWidth = lineMetrics.underlineWidth / 2.0f;
const auto startX = target.x + halfUnderlineWidth;
const auto endX = target.x + fullRunWidth - halfUnderlineWidth;
const auto y = target.y + lineMetrics.underlineOffset;
if (WI_IsFlagSet(lines, GridLines::Underline))
if (lines.test(GridLines::Underline))
{
DrawLine(startX, y, endX, y, lineMetrics.underlineWidth);
}
if (WI_IsFlagSet(lines, GridLines::HyperlinkUnderline))
if (lines.test(GridLines::HyperlinkUnderline))
{
DrawHyperlinkLine(startX, y, endX, y, lineMetrics.underlineWidth);
}
if (WI_IsFlagSet(lines, GridLines::DoubleUnderline))
if (lines.test(GridLines::DoubleUnderline))
{
DrawLine(startX, y, endX, y, lineMetrics.underlineWidth);
const auto y2 = target.y + lineMetrics.underlineOffset2;
@ -1804,7 +1805,7 @@ try
}
}
if (WI_IsFlagSet(lines, GridLines::Strikethrough))
if (lines.test(GridLines::Strikethrough))
{
const auto halfStrikethroughWidth = lineMetrics.strikethroughWidth / 2.0f;
const auto startX = target.x + halfStrikethroughWidth;

View file

@ -100,7 +100,7 @@ namespace Microsoft::Console::Render
bool const fTrimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLines const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;

View file

@ -52,7 +52,7 @@ namespace Microsoft::Console::Render
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLines lines,
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines,
const COLORREF color,
const size_t cchLine,
const COORD coordTarget) noexcept override;

View file

@ -472,7 +472,7 @@ using namespace Microsoft::Console::Render;
// - coordTarget - The starting X/Y position of the first character to draw on.
// Return Value:
// - S_OK or suitable GDI HRESULT error or E_FAIL for GDI errors in functions that don't reliably return a specific error code.
[[nodiscard]] HRESULT GdiEngine::PaintBufferGridLines(const GridLines lines, const COLORREF color, const size_t cchLine, const COORD coordTarget) noexcept
[[nodiscard]] HRESULT GdiEngine::PaintBufferGridLines(const GridLineSet lines, const COLORREF color, const size_t cchLine, const COORD coordTarget) noexcept
{
LOG_IF_FAILED(_FlushBufferLines());
@ -499,7 +499,7 @@ using namespace Microsoft::Console::Render;
return PatBlt(_hdcMemoryContext, x, y, w, h, PATCOPY);
};
if (lines & GridLines::Left)
if (lines.test(GridLines::Left))
{
auto x = ptTarget.x;
for (size_t i = 0; i < cchLine; i++, x += fontWidth)
@ -508,7 +508,7 @@ using namespace Microsoft::Console::Render;
}
}
if (lines & GridLines::Right)
if (lines.test(GridLines::Right))
{
// NOTE: We have to subtract the stroke width from the cell width
// to ensure the x coordinate remains inside the clipping rectangle.
@ -519,13 +519,13 @@ using namespace Microsoft::Console::Render;
}
}
if (lines & GridLines::Top)
if (lines.test(GridLines::Top))
{
const auto y = ptTarget.y;
RETURN_HR_IF(E_FAIL, !DrawLine(ptTarget.x, y, widthOfAllCells, _lineMetrics.gridlineWidth));
}
if (lines & GridLines::Bottom)
if (lines.test(GridLines::Bottom))
{
// NOTE: We have to subtract the stroke width from the cell height
// to ensure the y coordinate remains inside the clipping rectangle.
@ -533,19 +533,19 @@ using namespace Microsoft::Console::Render;
RETURN_HR_IF(E_FAIL, !DrawLine(ptTarget.x, y, widthOfAllCells, _lineMetrics.gridlineWidth));
}
if (lines & (GridLines::Underline | GridLines::DoubleUnderline))
if (lines.any(GridLines::Underline, GridLines::DoubleUnderline))
{
const auto y = ptTarget.y + _lineMetrics.underlineOffset;
RETURN_HR_IF(E_FAIL, !DrawLine(ptTarget.x, y, widthOfAllCells, _lineMetrics.underlineWidth));
if (lines & GridLines::DoubleUnderline)
if (lines.test(GridLines::DoubleUnderline))
{
const auto y2 = ptTarget.y + _lineMetrics.underlineOffset2;
RETURN_HR_IF(E_FAIL, !DrawLine(ptTarget.x, y2, widthOfAllCells, _lineMetrics.underlineWidth));
}
}
if (lines & GridLines::Strikethrough)
if (lines.test(GridLines::Strikethrough))
{
const auto y = ptTarget.y + _lineMetrics.strikethroughOffset;
RETURN_HR_IF(E_FAIL, !DrawLine(ptTarget.x, y, widthOfAllCells, _lineMetrics.strikethroughWidth));

View file

@ -30,18 +30,19 @@ namespace Microsoft::Console::Render
class IRenderEngine
{
public:
enum GridLines
enum class GridLines
{
None = 0x0,
Top = 0x1,
Bottom = 0x2,
Left = 0x4,
Right = 0x8,
Underline = 0x10,
DoubleUnderline = 0x20,
Strikethrough = 0x40,
HyperlinkUnderline = 0x80
None,
Top,
Bottom,
Left,
Right,
Underline,
DoubleUnderline,
Strikethrough,
HyperlinkUnderline
};
using GridLineSet = til::enumset<GridLines>;
virtual ~IRenderEngine() = 0;
@ -86,7 +87,7 @@ namespace Microsoft::Console::Render
const COORD coord,
const bool fTrimLeft,
const bool lineWrapped) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBufferGridLines(const GridLines lines,
[[nodiscard]] virtual HRESULT PaintBufferGridLines(const GridLineSet lines,
const COLORREF color,
const size_t cchLine,
const COORD coordTarget) noexcept = 0;
@ -118,5 +119,3 @@ namespace Microsoft::Console::Render
inline Microsoft::Console::Render::IRenderEngine::~IRenderEngine() {}
}
DEFINE_ENUM_FLAG_OPERATORS(Microsoft::Console::Render::IRenderEngine::GridLines)

View file

@ -324,7 +324,7 @@ CATCH_RETURN();
// - coordTarget - <unused>
// Return Value:
// - S_FALSE
[[nodiscard]] HRESULT UiaEngine::PaintBufferGridLines(GridLines const /*lines*/,
[[nodiscard]] HRESULT UiaEngine::PaintBufferGridLines(GridLineSet const /*lines*/,
COLORREF const /*color*/,
size_t const /*cchLine*/,
COORD const /*coordTarget*/) noexcept

View file

@ -55,7 +55,7 @@ namespace Microsoft::Console::Render
COORD const coord,
bool const fTrimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLines const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;

View file

@ -142,7 +142,7 @@ using namespace Microsoft::Console::Types;
// - coordTarget - The starting X/Y position of the first character to draw on.
// Return Value:
// - S_OK
[[nodiscard]] HRESULT VtEngine::PaintBufferGridLines(const GridLines /*lines*/,
[[nodiscard]] HRESULT VtEngine::PaintBufferGridLines(const GridLineSet /*lines*/,
const COLORREF /*color*/,
const size_t /*cchLine*/,
const COORD /*coordTarget*/) noexcept

View file

@ -65,7 +65,7 @@ namespace Microsoft::Console::Render
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLines lines,
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines,
const COLORREF color,
const size_t cchLine,
const COORD coordTarget) noexcept override;

View file

@ -287,7 +287,7 @@ bool WddmConEngine::IsInitialized()
CATCH_RETURN();
}
[[nodiscard]] HRESULT WddmConEngine::PaintBufferGridLines(GridLines const /*lines*/,
[[nodiscard]] HRESULT WddmConEngine::PaintBufferGridLines(GridLineSet const /*lines*/,
COLORREF const /*color*/,
size_t const /*cchLine*/,
COORD const /*coordTarget*/) noexcept

View file

@ -45,7 +45,7 @@ namespace Microsoft::Console::Render
const COORD coord,
const bool trimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLines const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;

View file

@ -21,6 +21,8 @@
#
# $ New-TerminalStackedChangelog origin/release-1.8..origin/release-1.9
#Requires -Version 7.0
[CmdletBinding()]
Param(
[string[]]$RevisionRanges