jesus what

This commit is contained in:
Mike Griese
2026-03-02 05:53:01 -06:00
parent 83d0d9df14
commit e8d1933b9e
46 changed files with 1068 additions and 16 deletions

View File

@@ -76,6 +76,36 @@
}
]
},
"OutputNotificationStyle": {
"oneOf": [
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string",
"enum": [
"taskbar",
"audible",
"tab",
"notification"
]
}
},
{
"type": "string",
"enum": [
"taskbar",
"audible",
"tab",
"notification",
"all",
"none"
]
}
]
},
"BellSound": {
"default": "",
"description": "Sets the file location of the sound played when the application emits a BEL character. If the path is invalid no sound will be played. This property also accepts an array of sounds and the terminal will pick one at random.",
@@ -94,6 +124,14 @@
}
]
},
"AutoDetectRunningCommand": {
"type": "string",
"enum": [
"disabled",
"automatic",
"progress"
]
},
"BuiltinSuggestionSource": {
"type": "string",
"anyOf": [
@@ -3174,6 +3212,21 @@
"mingw"
],
"type": "string"
},
"notifyOnInactiveOutput": {
"default": "none",
"description": "Controls how the terminal notifies you when a background pane produces output. Supported values include `taskbar`, `audible`, `tab`, and `notification`. Can be set to true (equivalent to `tab`), false/none (disabled), a single string, or an array of strings.",
"$ref": "#/$defs/OutputNotificationStyle"
},
"notifyOnNextPrompt": {
"default": "none",
"description": "Controls how the terminal notifies you when a running command finishes and the shell returns to a prompt. Requires shell integration. Supported values include `taskbar`, `audible`, `tab`, and `notification`. Can be set to true (equivalent to `tab`), false/none (disabled), a single string, or an array of strings.",
"$ref": "#/$defs/OutputNotificationStyle"
},
"autoDetectRunningCommand": {
"default": "disabled",
"description": "Controls automatic detection of running commands via shell integration marks. When set to `automatic`, an indeterminate progress indicator is shown on the tab while a command is executing. When set to `progress`, the terminal will also attempt to detect progress percentages from command output. Requires shell integration.",
"$ref": "#/$defs/AutoDetectRunningCommand"
}
}
},

View File

@@ -10,6 +10,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<> ConnectionStateChanged;
til::typed_event<IPaneContent> CloseRequested;
til::typed_event<IPaneContent, winrt::TerminalApp::BellEventArgs> BellRequested;
til::typed_event<IPaneContent, winrt::TerminalApp::NotificationEventArgs> NotificationRequested;
til::typed_event<IPaneContent> TitleChanged;
til::typed_event<IPaneContent> TabColorChanged;
til::typed_event<IPaneContent> TaskbarProgressChanged;

View File

@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DesktopNotification.h"
using namespace winrt::Windows::UI::Notifications;
using namespace winrt::Windows::Data::Xml::Dom;
namespace winrt::TerminalApp::implementation
{
std::atomic<int64_t> DesktopNotification::_lastNotificationTime{ 0 };
bool DesktopNotification::ShouldSendNotification()
{
FILETIME ft{};
GetSystemTimeAsFileTime(&ft);
const auto now = (static_cast<int64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
auto last = _lastNotificationTime.load(std::memory_order_relaxed);
if (now - last < MinNotificationIntervalTicks)
{
return false;
}
// Attempt to update; if another thread beat us, that's fine — we'll skip this one.
_lastNotificationTime.compare_exchange_strong(last, now, std::memory_order_relaxed);
return true;
}
void DesktopNotification::SendNotification(
const DesktopNotificationArgs& args,
std::function<void(uint32_t tabIndex)> activated)
{
try
{
if (!ShouldSendNotification())
{
return;
}
// Build the toast XML. We use a simple template with a title and body text.
//
// <toast launch="tabIndex=N">
// <visual>
// <binding template="ToastGeneric">
// <text>Title</text>
// <text>Message</text>
// </binding>
// </visual>
// </toast>
auto toastXml = ToastNotificationManager::GetTemplateContent(ToastTemplateType::ToastText02);
auto textNodes = toastXml.GetElementsByTagName(L"text");
// First <text> is the title
textNodes.Item(0).InnerText(args.Title);
// Second <text> is the body
textNodes.Item(1).InnerText(args.Message);
// Set launch args so we can identify which tab to activate.
auto toastElement = toastXml.DocumentElement();
toastElement.SetAttribute(L"launch", fmt::format(FMT_COMPILE(L"tabIndex={}"), args.TabIndex));
// Set the scenario to "reminder" to ensure the toast shows even in DND,
// and the group/tag to allow replacement of repeated notifications.
toastElement.SetAttribute(L"scenario", L"default");
auto toast = ToastNotification{ toastXml };
// Set the tag and group to enable notification replacement.
// Using the tab index as a tag means repeated output from the same tab
// replaces the previous notification rather than stacking.
toast.Tag(fmt::format(FMT_COMPILE(L"wt-tab-{}"), args.TabIndex));
toast.Group(L"WindowsTerminal");
// When the user activates (clicks) the toast, fire the callback.
if (activated)
{
const auto tabIndex = args.TabIndex;
toast.Activated([activated, tabIndex](const auto& /*sender*/, const auto& /*eventArgs*/) {
activated(tabIndex);
});
}
// For packaged apps, CreateToastNotifier() uses the package identity automatically.
// For unpackaged apps, we need to provide an AUMID, but that case is less common
// and toast notifications may not be supported without additional setup.
auto notifier = ToastNotificationManager::CreateToastNotifier();
notifier.Show(toast);
}
catch (...)
{
// Toast notification is a best-effort feature. If it fails (e.g., notifications
// are disabled, or the app is unpackaged without proper AUMID setup), we silently
// ignore the error.
LOG_CAUGHT_EXCEPTION();
}
}
}

View File

@@ -0,0 +1,52 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- DesktopNotification.h
Module Description:
- Helper for sending Windows desktop toast notifications. Used by the
`OutputNotificationStyle::Notification` flag to surface activity
and prompt-return events to the user via the Windows notification center.
--*/
#pragma once
#include "pch.h"
namespace winrt::TerminalApp::implementation
{
struct DesktopNotificationArgs
{
winrt::hstring Title;
winrt::hstring Message;
uint32_t TabIndex{ 0 };
};
class DesktopNotification
{
public:
// Sends a toast notification with the given title and message.
// When the user clicks the toast, the `Activated` callback fires
// with the tabIndex that was passed in, so the caller can switch
// to the correct tab and summon the window.
//
// activated: A callback invoked on the background thread when the
// toast is clicked. The uint32_t parameter is the tab index.
static void SendNotification(
const DesktopNotificationArgs& args,
std::function<void(uint32_t tabIndex)> activated);
// Rate-limits toast notifications so we don't spam the user.
// Returns true if a notification is allowed, false if too recent.
static bool ShouldSendNotification();
private:
static std::atomic<int64_t> _lastNotificationTime;
// Minimum interval between notifications, in 100ns ticks (FILETIME units).
// 5 seconds = 5 * 10,000,000
static constexpr int64_t MinNotificationIntervalTicks = 50'000'000LL;
};
}

View File

@@ -16,6 +16,11 @@ namespace TerminalApp
Boolean FlashTaskbar { get; };
};
runtimeclass NotificationEventArgs
{
Microsoft.Terminal.Control.OutputNotificationStyle Style { get; };
};
interface IPaneContent
{
Windows.UI.Xaml.FrameworkElement GetRoot();
@@ -41,6 +46,7 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> ConnectionStateChanged;
event Windows.Foundation.TypedEventHandler<IPaneContent, BellEventArgs> BellRequested;
event Windows.Foundation.TypedEventHandler<IPaneContent, NotificationEventArgs> NotificationRequested;
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> TitleChanged;
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<IPaneContent, Object> TaskbarProgressChanged;

View File

@@ -923,4 +923,16 @@
<data name="InvalidRegex" xml:space="preserve">
<value>An invalid regular expression was found.</value>
</data>
<data name="NotificationTitle" xml:space="preserve">
<value>Windows Terminal</value>
<comment>Title shown in desktop toast notifications for tab activity.</comment>
</data>
<data name="NotificationMessage_TabActivity" xml:space="preserve">
<value>Tab "{0}" has new activity</value>
<comment>{Locked="{0}"}Message shown in a desktop toast notification when a tab produces output. {0} is the tab title.</comment>
</data>
<data name="NotificationMessage_TabActivityInWindow" xml:space="preserve">
<value>Tab "{0}" in {1} has new activity</value>
<comment>{Locked="{0}"}{Locked="{1}"}Message shown in a desktop toast notification when a tab produces output. {0} is the tab title. {1} is the window name.</comment>
</data>
</root>

View File

@@ -123,6 +123,15 @@ namespace winrt::TerminalApp::implementation
_bellIndicatorTimer.Stop();
}
// Method Description:
// - Called when the timer for the activity indicator in the tab header fires
// - Removes the activity indicator from the tab header
void Tab::_ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& /*sender*/, const Windows::Foundation::IInspectable& /*e*/)
{
ShowActivityIndicator(false);
_activityIndicatorTimer.Stop();
}
// Method Description:
// - Initializes a TabViewItem for this Tab instance.
// Arguments:
@@ -329,6 +338,11 @@ namespace winrt::TerminalApp::implementation
{
ShowBellIndicator(false);
}
// When we gain focus, remove the activity indicator if it is active
if (_tabStatus.ActivityIndicator())
{
ShowActivityIndicator(false);
}
}
}
@@ -459,6 +473,29 @@ namespace winrt::TerminalApp::implementation
_bellIndicatorTimer.Start();
}
void Tab::ShowActivityIndicator(const bool show)
{
ASSERT_UI_THREAD();
_tabStatus.ActivityIndicator(show);
}
// Method Description:
// - Activates the timer for the activity indicator in the tab
// - Called if a notification was raised when the tab already has focus
void Tab::ActivateActivityIndicatorTimer()
{
ASSERT_UI_THREAD();
if (!_activityIndicatorTimer)
{
_activityIndicatorTimer.Interval(std::chrono::milliseconds(2000));
_activityIndicatorTimer.Tick({ get_weak(), &Tab::_ActivityIndicatorTimerTick });
}
_activityIndicatorTimer.Start();
}
// Method Description:
// - Gets the title string of the last focused terminal control in our tree.
// Returns the empty string if there is no such control.
@@ -1161,6 +1198,54 @@ namespace winrt::TerminalApp::implementation
}
});
events.NotificationRequested = content.NotificationRequested(
winrt::auto_revoke,
[dispatcher, weakThis](TerminalApp::IPaneContent sender, auto notifArgs) -> safe_void_coroutine {
const auto weakThisCopy = weakThis;
co_await wil::resume_foreground(dispatcher);
if (const auto tab{ weakThisCopy.get() })
{
// For NotifyOnInactiveOutput, only show notifications if this sender
// is NOT the currently active pane content. For NotifyOnNextPrompt,
// the notification is always relevant.
const auto activeContent = tab->GetActiveContent();
const auto isActivePaneContent = activeContent && activeContent == sender;
const auto style = notifArgs.Style();
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Taskbar))
{
// Flash the taskbar button
tab->TabRaiseVisualBell.raise();
}
// Audible notification is handled in TerminalPaneContent already
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Tab))
{
// Show the activity indicator in the tab header (distinct from bell)
// Only for inactive pane output, skip if this is the focused pane in a focused tab
if (!isActivePaneContent || tab->_focusState == WUX::FocusState::Unfocused)
{
tab->ShowActivityIndicator(true);
if (tab->_focusState != WUX::FocusState::Unfocused)
{
tab->ActivateActivityIndicatorTimer();
}
}
}
if (WI_IsFlagSet(style, winrt::Microsoft::Terminal::Control::OutputNotificationStyle::Notification))
{
// Request a desktop toast notification.
// TerminalPage subscribes to this event and handles sending the toast
// and processing its activation (summoning the window + switching tabs).
tab->TabToastNotificationRequested.raise(tab->Title(), tab->TabViewIndex());
}
}
});
if (const auto& terminal{ content.try_as<TerminalApp::TerminalPaneContent>() })
{
events.RestartTerminalRequested = terminal.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &Tab::_bubbleRestartTerminalRequested });
@@ -1393,6 +1478,11 @@ namespace winrt::TerminalApp::implementation
{
tab->ShowBellIndicator(false);
}
// Also remove the activity indicator
if (tab->_tabStatus.ActivityIndicator())
{
tab->ShowActivityIndicator(false);
}
}
});

View File

@@ -48,6 +48,9 @@ namespace winrt::TerminalApp::implementation
void ShowBellIndicator(const bool show);
void ActivateBellIndicatorTimer();
void ShowActivityIndicator(const bool show);
void ActivateActivityIndicatorTimer();
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;
std::optional<winrt::Microsoft::Terminal::Settings::Model::SplitDirection> PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitDirection splitType,
const float splitSize,
@@ -121,6 +124,7 @@ namespace winrt::TerminalApp::implementation
til::typed_event<TerminalApp::Tab, IInspectable> ActivePaneChanged;
til::event<winrt::delegate<>> TabRaiseVisualBell;
til::event<winrt::delegate<winrt::hstring /*title*/, uint32_t /*tabIndex*/>> TabToastNotificationRequested;
til::typed_event<IInspectable, IInspectable> TaskbarProgressChanged;
// The TabViewIndex is the index this Tab object resides in TerminalPage's _tabs vector.
@@ -176,6 +180,7 @@ namespace winrt::TerminalApp::implementation
struct ContentEventTokens
{
winrt::TerminalApp::IPaneContent::BellRequested_revoker BellRequested;
winrt::TerminalApp::IPaneContent::NotificationRequested_revoker NotificationRequested;
winrt::TerminalApp::IPaneContent::TitleChanged_revoker TitleChanged;
winrt::TerminalApp::IPaneContent::TabColorChanged_revoker TabColorChanged;
winrt::TerminalApp::IPaneContent::TaskbarProgressChanged_revoker TaskbarProgressChanged;
@@ -210,6 +215,9 @@ namespace winrt::TerminalApp::implementation
SafeDispatcherTimer _bellIndicatorTimer;
void _BellIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
SafeDispatcherTimer _activityIndicatorTimer;
void _ActivityIndicatorTimerTick(const Windows::Foundation::IInspectable& sender, const Windows::Foundation::IInspectable& e);
void _UpdateHeaderControlMaxWidth();
void _CreateContextMenu();

View File

@@ -32,6 +32,12 @@
FontSize="12"
Glyph="&#xEA8F;"
Visibility="{x:Bind TabStatus.BellIndicator, Mode=OneWay}" />
<FontIcon x:Name="HeaderActivityIndicator"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="8"
Glyph="&#xF127;"
Visibility="{x:Bind TabStatus.ActivityIndicator, Mode=OneWay}" />
<FontIcon x:Name="HeaderZoomIcon"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"

View File

@@ -19,6 +19,7 @@
#include "DebugTapConnection.h"
#include "..\TerminalSettingsModel\FileUtils.h"
#include "../TerminalSettingsAppAdapterLib/TerminalSettings.h"
#include "DesktopNotification.h"
#include <shlobj.h>
@@ -150,6 +151,15 @@ namespace winrt::TerminalApp::implementation
}
});
// When a tab requests a desktop toast notification (OutputNotificationStyle::Notification),
// send the toast and handle activation by summoning this window and switching to the tab.
newTabImpl->TabToastNotificationRequested([weakThis{ get_weak() }](const winrt::hstring& title, uint32_t tabIndex) {
if (const auto page{ weakThis.get() })
{
page->_SendDesktopNotification(title, tabIndex);
}
});
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().InsertAt(insertPosition, tabViewItem);
@@ -1185,4 +1195,54 @@ namespace winrt::TerminalApp::implementation
{
return _tabs.Size() > 1;
}
// Method Description:
// - Sends a Windows desktop toast notification for a tab. When the user clicks
// the toast, summon this window and switch to the specified tab.
// Arguments:
// - tabTitle: The title of the tab to display in the notification.
// - tabIndex: The index of the tab to switch to when the toast is activated.
void TerminalPage::_SendDesktopNotification(const winrt::hstring& tabTitle, uint32_t tabIndex)
{
// Build the notification message.
// Use the window name if available for context, otherwise just use the tab title.
const auto windowName = _WindowProperties ? _WindowProperties.WindowNameForDisplay() : winrt::hstring{};
winrt::hstring message;
if (!windowName.empty())
{
message = RS_fmt(L"NotificationMessage_TabActivityInWindow", std::wstring_view{ tabTitle }, std::wstring_view{ windowName });
}
else
{
message = RS_fmt(L"NotificationMessage_TabActivity", std::wstring_view{ tabTitle });
}
implementation::DesktopNotificationArgs args;
args.Title = RS_(L"NotificationTitle");
args.Message = message;
args.TabIndex = tabIndex;
// Capture a weak ref and the dispatcher so we can marshal back to the UI thread
// when the toast is activated.
auto weakThis = get_weak();
auto dispatcher = Dispatcher();
implementation::DesktopNotification::SendNotification(
args,
[weakThis, dispatcher, tabIndex](uint32_t /*activatedTabIndex*/) -> void {
// The toast Activated callback fires on a background thread.
// We need to dispatch to the UI thread to summon the window and switch tabs.
[](auto weakThis, auto dispatcher, auto tabIndex) -> safe_void_coroutine {
co_await wil::resume_foreground(dispatcher);
if (const auto page{ weakThis.get() })
{
// Summon this window (bring to foreground)
page->SummonWindowRequested.raise(nullptr, nullptr);
// Switch to the tab that triggered the notification
page->_SelectTab(tabIndex);
}
}(weakThis, dispatcher, tabIndex);
});
}
}

View File

@@ -173,6 +173,7 @@
<ClInclude Include="SettingsPaneContent.h">
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClInclude>
<ClInclude Include="DesktopNotification.h" />
<ClInclude Include="Toast.h" />
<ClInclude Include="TerminalSettingsCache.h" />
<ClInclude Include="SuggestionsControl.h">
@@ -286,6 +287,7 @@
<DependentUpon>TerminalPaneContent.idl</DependentUpon>
</ClCompile>
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="DesktopNotification.cpp" />
<ClCompile Include="Toast.cpp" />
<ClCompile Include="TerminalSettingsCache.cpp" />
<ClCompile Include="SuggestionsControl.cpp">

View File

@@ -30,6 +30,7 @@
<ClCompile Include="fzf/fzf.cpp">
<Filter>fzf</Filter>
</ClCompile>
<ClCompile Include="DesktopNotification.cpp" />
<ClCompile Include="Toast.cpp" />
<ClCompile Include="LanguageProfileNotifier.cpp" />
<ClCompile Include="TerminalSettingsCache.cpp" />
@@ -58,6 +59,7 @@
<ClInclude Include="fzf/fzf.h">
<Filter>fzf</Filter>
</ClInclude>
<ClInclude Include="DesktopNotification.h" />
<ClInclude Include="Toast.h" />
<ClInclude Include="LanguageProfileNotifier.h" />
<ClInclude Include="WindowsPackageManagerFactory.h" />

View File

@@ -570,6 +570,8 @@ namespace winrt::TerminalApp::implementation
void _activePaneChanged(winrt::TerminalApp::Tab tab, Windows::Foundation::IInspectable args);
safe_void_coroutine _doHandleSuggestions(Microsoft::Terminal::Settings::Model::SuggestionsArgs realArgs);
void _SendDesktopNotification(const winrt::hstring& tabTitle, uint32_t tabIndex);
#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);

View File

@@ -10,6 +10,7 @@
#include "../../types/inc/utils.hpp"
#include "BellEventArgs.g.cpp"
#include "NotificationEventArgs.g.cpp"
#include "TerminalPaneContent.g.cpp"
using namespace winrt::Windows::Foundation;
@@ -34,8 +35,11 @@ namespace winrt::TerminalApp::implementation
{
_controlEvents._ConnectionStateChanged = _control.ConnectionStateChanged(winrt::auto_revoke, { this, &TerminalPaneContent::_controlConnectionStateChangedHandler });
_controlEvents._WarningBell = _control.WarningBell(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlWarningBellHandler });
_controlEvents._PromptReturned = _control.PromptReturned(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlPromptReturnedHandler });
_controlEvents._CommandStarted = _control.CommandStarted(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlCommandStartedHandler });
_controlEvents._CloseTerminalRequested = _control.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_closeTerminalRequestedHandler });
_controlEvents._RestartTerminalRequested = _control.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_restartTerminalRequestedHandler });
_controlEvents._OutputIdle = _control.OutputIdle(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlOutputIdleHandler });
_controlEvents._TitleChanged = _control.TitleChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTitleChanged });
_controlEvents._TabColorChanged = _control.TabColorChanged(winrt::auto_revoke, { get_weak(), &TerminalPaneContent::_controlTabColorChanged });
@@ -298,6 +302,119 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Returns the taskbar state, accounting for auto-detected running command progress.
// VT-set progress (OSC 9;4) takes precedence over auto-detected progress.
uint64_t TerminalPaneContent::TaskbarState()
{
const auto vtState = _control.TaskbarState();
// VT-set progress takes precedence over auto-detected progress
if (vtState != 0)
{
return vtState;
}
// Auto-detected indeterminate progress (between command start and prompt return)
if (_autoDetectActive)
{
return 3; // TaskbarState::Indeterminate
}
return 0;
}
// Method Description:
// - Returns the taskbar progress, accounting for auto-detected running command progress.
uint64_t TerminalPaneContent::TaskbarProgress()
{
const auto vtState = _control.TaskbarState();
// VT-set progress takes precedence
if (vtState != 0)
{
return _control.TaskbarProgress();
}
return 0;
}
// Method Description:
// - Raised when a shell integration prompt mark (133;A) is received, indicating
// the command has finished and we're back at a prompt.
// - Checks NotifyOnNextPrompt setting and raises NotificationRequested.
// - If autoDetectRunningCommand is enabled, clears the indeterminate progress ring.
void TerminalPaneContent::_controlPromptReturnedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (_profile)
{
// Check NotifyOnNextPrompt setting and raise a notification
const auto notifyStyle = _profile.NotifyOnNextPrompt();
if (static_cast<int>(notifyStyle) != 0)
{
// Play audible notification if requested (handle here like BellStyle::Audible)
if (WI_IsFlagSet(notifyStyle, OutputNotificationStyle::Audible))
{
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
// Raise NotificationRequested so Tab can handle Taskbar/Tab/Notification flags
NotificationRequested.raise(*this,
*winrt::make_self<TerminalApp::implementation::NotificationEventArgs>(notifyStyle));
}
// If autoDetectRunningCommand is enabled, clear the progress ring
const auto autoDetect = _profile.AutoDetectRunningCommand();
if (autoDetect != AutoDetectRunningCommand::Disabled && _autoDetectActive)
{
_autoDetectActive = false;
TaskbarProgressChanged.raise(*this, nullptr);
}
}
}
// Method Description:
// - Raised when a shell integration command output mark (133;C) is received,
// indicating a command has started executing.
// - If autoDetectRunningCommand is enabled, shows an indeterminate progress ring.
void TerminalPaneContent::_controlCommandStartedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (_profile)
{
const auto autoDetect = _profile.AutoDetectRunningCommand();
if (autoDetect != AutoDetectRunningCommand::Disabled && !_autoDetectActive)
{
_autoDetectActive = true;
TaskbarProgressChanged.raise(*this, nullptr);
}
}
}
// Method Description:
// - Raised when output stops being produced for ~100ms (debounced).
// Used to detect output in inactive panes for NotifyOnInactiveOutput.
// - Raises NotificationRequested so Tab can show activity indicators.
void TerminalPaneContent::_controlOutputIdleHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*eventArgs*/)
{
if (_profile)
{
const auto notifyStyle = _profile.NotifyOnInactiveOutput();
if (static_cast<int>(notifyStyle) != 0)
{
// Play audible notification if requested
if (WI_IsFlagSet(notifyStyle, OutputNotificationStyle::Audible))
{
const auto soundAlias = reinterpret_cast<LPCTSTR>(SND_ALIAS_SYSTEMHAND);
PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY);
}
// Raise NotificationRequested so Tab can handle Taskbar/Tab flags.
// Tab will check if this pane is the active pane and skip if so.
NotificationRequested.raise(*this,
*winrt::make_self<TerminalApp::implementation::NotificationEventArgs>(notifyStyle));
}
}
}
safe_void_coroutine TerminalPaneContent::_playBellSound(winrt::Windows::Foundation::Uri uri)
{
auto weakThis{ get_weak() };

View File

@@ -4,6 +4,7 @@
#pragma once
#include "TerminalPaneContent.g.h"
#include "BellEventArgs.g.h"
#include "NotificationEventArgs.g.h"
#include "BasicPaneEvents.h"
namespace winrt::TerminalApp::implementation
@@ -19,6 +20,15 @@ namespace winrt::TerminalApp::implementation
til::property<bool> FlashTaskbar;
};
struct NotificationEventArgs : public NotificationEventArgsT<NotificationEventArgs>
{
public:
NotificationEventArgs(winrt::Microsoft::Terminal::Control::OutputNotificationStyle style) :
Style(style) {}
til::property<winrt::Microsoft::Terminal::Control::OutputNotificationStyle> Style;
};
struct TerminalPaneContent : TerminalPaneContentT<TerminalPaneContent>, BasicPaneEvents
{
TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile,
@@ -43,8 +53,8 @@ namespace winrt::TerminalApp::implementation
}
winrt::hstring Title() { return _control.Title(); }
uint64_t TaskbarState() { return _control.TaskbarState(); }
uint64_t TaskbarProgress() { return _control.TaskbarProgress(); }
uint64_t TaskbarState();
uint64_t TaskbarProgress();
bool ReadOnly() { return _control.ReadOnly(); }
winrt::hstring Icon() const;
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() const noexcept;
@@ -66,11 +76,15 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
bool _bellPlayerCreated{ false };
bool _autoDetectActive{ false };
struct ControlEventTokens
{
winrt::Microsoft::Terminal::Control::TermControl::ConnectionStateChanged_revoker _ConnectionStateChanged;
winrt::Microsoft::Terminal::Control::TermControl::WarningBell_revoker _WarningBell;
winrt::Microsoft::Terminal::Control::TermControl::PromptReturned_revoker _PromptReturned;
winrt::Microsoft::Terminal::Control::TermControl::CommandStarted_revoker _CommandStarted;
winrt::Microsoft::Terminal::Control::TermControl::OutputIdle_revoker _OutputIdle;
winrt::Microsoft::Terminal::Control::TermControl::CloseTerminalRequested_revoker _CloseTerminalRequested;
winrt::Microsoft::Terminal::Control::TermControl::RestartTerminalRequested_revoker _RestartTerminalRequested;
@@ -89,6 +103,12 @@ namespace winrt::TerminalApp::implementation
safe_void_coroutine _controlConnectionStateChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& /*args*/);
void _controlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _controlPromptReturnedHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _controlCommandStartedHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _controlOutputIdleHandler(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::Foundation::IInspectable& e);
void _controlReadOnlyChangedHandler(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& e);
void _controlTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);

View File

@@ -17,6 +17,7 @@ namespace winrt::TerminalApp::implementation
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, BellIndicator, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, ActivityIndicator, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsReadOnlyActive, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(uint32_t, ProgressValue, PropertyChanged.raise);
WINRT_OBSERVABLE_PROPERTY(bool, IsInputBroadcastActive, PropertyChanged.raise);

View File

@@ -12,6 +12,7 @@ namespace TerminalApp
Boolean IsProgressRingActive { get; set; };
Boolean IsProgressRingIndeterminate { get; set; };
Boolean BellIndicator { get; set; };
Boolean ActivityIndicator { get; set; };
UInt32 ProgressValue { get; set; };
Boolean IsReadOnlyActive { get; set; };
Boolean IsInputBroadcastActive { get; set; };

View File

@@ -54,6 +54,9 @@
#include <winrt/Windows.Media.Playback.h>
#include <winrt/Windows.Management.Deployment.h>
#include <winrt/Windows.UI.Notifications.h>
#include <winrt/Windows.Data.Xml.Dom.h>
#include <winrt/Microsoft.UI.Xaml.Controls.h>
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>

View File

@@ -118,6 +118,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnWarningBell = [this] { _terminalWarningBell(); };
_terminal->SetWarningBellCallback(pfnWarningBell);
auto pfnPromptReturned = [this] { _terminalPromptReturned(); };
_terminal->SetPromptReturnedCallback(pfnPromptReturned);
auto pfnCommandStarted = [this] { _terminalCommandStarted(); };
_terminal->SetCommandStartedCallback(pfnCommandStarted);
auto pfnTitleChanged = [this](auto&& PH1) { _terminalTitleChanged(std::forward<decltype(PH1)>(PH1)); };
_terminal->SetTitleChangedCallback(pfnTitleChanged);
@@ -1593,6 +1599,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WarningBell.raise(*this, nullptr);
}
void ControlCore::_terminalPromptReturned()
{
// Since this can only ever be triggered by output from the connection,
// then the Terminal already has the write lock when calling this
// callback.
PromptReturned.raise(*this, nullptr);
}
void ControlCore::_terminalCommandStarted()
{
// Since this can only ever be triggered by output from the connection,
// then the Terminal already has the write lock when calling this
// callback.
CommandStarted.raise(*this, nullptr);
}
// Method Description:
// - Called for the Terminal's TitleChanged callback. This will re-raise
// a new winrt TypedEvent that can be listened to.

View File

@@ -276,6 +276,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<IInspectable, Control::TitleChangedEventArgs> TitleChanged;
til::typed_event<IInspectable, Control::WriteToClipboardEventArgs> WriteToClipboard;
til::typed_event<> WarningBell;
til::typed_event<> PromptReturned;
til::typed_event<> CommandStarted;
til::typed_event<> TabColorChanged;
til::typed_event<> BackgroundColorChanged;
til::typed_event<IInspectable, Control::ScrollPositionChangedArgs> ScrollPositionChanged;
@@ -324,6 +326,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
#pragma region TerminalCoreCallbacks
void _terminalWarningBell();
void _terminalPromptReturned();
void _terminalCommandStarted();
void _terminalTitleChanged(std::wstring_view wstr);
void _terminalScrollPositionChanged(const int viewTop,
const int viewHeight,

View File

@@ -191,6 +191,8 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, WriteToClipboardEventArgs> WriteToClipboard;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
event Windows.Foundation.TypedEventHandler<Object, Object> PromptReturned;
event Windows.Foundation.TypedEventHandler<Object, Object> CommandStarted;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> BackgroundColorChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;

View File

@@ -29,6 +29,23 @@ namespace Microsoft.Terminal.Control
MinGW,
};
[flags]
enum OutputNotificationStyle
{
Taskbar = 0x1,
Audible = 0x2,
Tab = 0x4,
Notification = 0x8,
All = 0xffffffff
};
enum AutoDetectRunningCommand
{
Disabled,
Automatic,
Progress
};
// Class Description:
// TerminalSettings encapsulates all settings that control the
// TermControl's behavior. In these settings there is both the entirety
@@ -77,6 +94,10 @@ namespace Microsoft.Terminal.Control
PathTranslationStyle PathTranslationStyle { get; };
OutputNotificationStyle NotifyOnInactiveOutput { get; };
OutputNotificationStyle NotifyOnNextPrompt { get; };
AutoDetectRunningCommand AutoDetectRunningCommand { get; };
// NOTE! When adding something here, make sure to update ControlProperties.h too!
};
}

View File

@@ -393,6 +393,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// attached content before we set up the throttled func, and that'll A/V
_revokers.coreScrollPositionChanged = _core.ScrollPositionChanged(winrt::auto_revoke, { get_weak(), &TermControl::_ScrollPositionChanged });
_revokers.WarningBell = _core.WarningBell(winrt::auto_revoke, { get_weak(), &TermControl::_coreWarningBell });
_revokers.PromptReturned = _core.PromptReturned(winrt::auto_revoke, { get_weak(), &TermControl::_corePromptReturned });
_revokers.CommandStarted = _core.CommandStarted(winrt::auto_revoke, { get_weak(), &TermControl::_coreCommandStarted });
static constexpr auto AutoScrollUpdateInterval = std::chrono::microseconds(static_cast<int>(1.0 / 30.0 * 1000000));
_autoScrollTimer.Interval(AutoScrollUpdateInterval);
@@ -3699,6 +3701,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_playWarningBell->Run();
}
void TermControl::_corePromptReturned(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
PromptReturned.raise(*this, nullptr);
}
void TermControl::_coreCommandStarted(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
CommandStarted.raise(*this, nullptr);
}
hstring TermControl::ReadEntireBuffer() const
{
return _core.ReadEntireBuffer();
@@ -3820,6 +3832,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void TermControl::_coreOutputIdle(const IInspectable& /*sender*/, const IInspectable& /*args*/)
{
_refreshSearch();
OutputIdle.raise(*this, nullptr);
}
void TermControl::OwningHwnd(uint64_t owner)

View File

@@ -212,6 +212,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
til::typed_event<IInspectable, IInspectable> FocusFollowMouseRequested;
til::typed_event<Control::TermControl, Windows::UI::Xaml::RoutedEventArgs> Initialized;
til::typed_event<> WarningBell;
til::typed_event<> PromptReturned;
til::typed_event<> CommandStarted;
til::typed_event<> OutputIdle;
til::typed_event<IInspectable, Control::KeySentEventArgs> KeySent;
til::typed_event<IInspectable, Control::CharSentEventArgs> CharSent;
til::typed_event<IInspectable, Control::StringSentEventArgs> StringSent;
@@ -425,6 +428,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
void _corePromptReturned(const IInspectable& sender, const IInspectable& args);
void _coreCommandStarted(const IInspectable& sender, const IInspectable& args);
void _coreOutputIdle(const IInspectable& sender, const IInspectable& args);
winrt::Windows::Foundation::Point _toPosInDips(const Core::Point terminalCellPos);
@@ -450,6 +455,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
Control::ControlCore::ScrollPositionChanged_revoker coreScrollPositionChanged;
Control::ControlCore::WarningBell_revoker WarningBell;
Control::ControlCore::PromptReturned_revoker PromptReturned;
Control::ControlCore::CommandStarted_revoker CommandStarted;
Control::ControlCore::RendererEnteredErrorState_revoker RendererEnteredErrorState;
Control::ControlCore::BackgroundColorChanged_revoker BackgroundColorChanged;
Control::ControlCore::FontSizeChanged_revoker FontSizeChanged;

View File

@@ -68,6 +68,9 @@ namespace Microsoft.Terminal.Control
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
event Windows.Foundation.TypedEventHandler<Object, NoticeEventArgs> RaiseNotice;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
event Windows.Foundation.TypedEventHandler<Object, Object> PromptReturned;
event Windows.Foundation.TypedEventHandler<Object, Object> CommandStarted;
event Windows.Foundation.TypedEventHandler<Object, Object> OutputIdle;
event Windows.Foundation.TypedEventHandler<Object, Object> HidePointerCursor;
event Windows.Foundation.TypedEventHandler<Object, Object> RestorePointerCursor;
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;

View File

@@ -1265,6 +1265,16 @@ void Microsoft::Terminal::Core::Terminal::SetClearQuickFixCallback(std::function
_pfnClearQuickFix.swap(pfn);
}
void Terminal::SetPromptReturnedCallback(std::function<void()> pfn) noexcept
{
_pfnPromptReturned.swap(pfn);
}
void Terminal::SetCommandStartedCallback(std::function<void()> pfn) noexcept
{
_pfnCommandStarted.swap(pfn);
}
// Method Description:
// - Stores the search highlighted regions in the terminal
void Terminal::SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept

View File

@@ -156,7 +156,7 @@ public:
bool IsVtInputEnabled() const noexcept override;
void NotifyBufferRotation(const int delta) override;
void NotifyShellIntegrationMark() override;
void NotifyShellIntegrationMark(ShellIntegrationMark mark) override;
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
@@ -232,6 +232,8 @@ public:
void SetSearchMissingCommandCallback(std::function<void(std::wstring_view, const til::CoordType)> pfn) noexcept;
void SetClearQuickFixCallback(std::function<void()> pfn) noexcept;
void SetWindowSizeChangedCallback(std::function<void(int32_t, int32_t)> pfn) noexcept;
void SetPromptReturnedCallback(std::function<void()> pfn) noexcept;
void SetCommandStartedCallback(std::function<void()> pfn) noexcept;
void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept;
void SetSearchHighlightFocused(size_t focusedIdx) noexcept;
void ScrollToSearchHighlight(til::CoordType searchScrollOffset);
@@ -340,6 +342,8 @@ private:
std::function<void(std::wstring_view, const til::CoordType)> _pfnSearchMissingCommand;
std::function<void()> _pfnClearQuickFix;
std::function<void(int32_t, int32_t)> _pfnWindowSizeChanged;
std::function<void()> _pfnPromptReturned;
std::function<void()> _pfnCommandStarted;
RenderSettings _renderSettings;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;

View File

@@ -400,8 +400,26 @@ void Terminal::NotifyBufferRotation(const int delta)
}
}
void Terminal::NotifyShellIntegrationMark()
void Terminal::NotifyShellIntegrationMark(ShellIntegrationMark mark)
{
// Notify the scrollbar that marks have been added so it can refresh the mark indicators
_NotifyScrollEvent();
switch (mark)
{
case ShellIntegrationMark::Prompt:
if (_pfnPromptReturned)
{
_pfnPromptReturned();
}
break;
case ShellIntegrationMark::Output:
if (_pfnCommandStarted)
{
_pfnCommandStarted();
}
break;
default:
break;
}
}

View File

@@ -353,6 +353,10 @@ namespace winrt::Microsoft::Terminal::Settings
_AllowVtChecksumReport = profile.AllowVtChecksumReport();
_AllowVtClipboardWrite = profile.AllowVtClipboardWrite();
_PathTranslationStyle = profile.PathTranslationStyle();
_NotifyOnInactiveOutput = profile.NotifyOnInactiveOutput();
_NotifyOnNextPrompt = profile.NotifyOnNextPrompt();
_AutoDetectRunningCommand = profile.AutoDetectRunningCommand();
}
// Method Description:

View File

@@ -40,6 +40,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(CloseOnExitMode, CloseOnExitMode, winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode, L"Profile_CloseOnExit", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(ScrollState, ScrollbarState, winrt::Microsoft::Terminal::Control::ScrollbarState, L"Profile_ScrollbarVisibility", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle, L"Profile_PathTranslationStyle", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(AutoDetectRunningCommand, AutoDetectRunningCommand, winrt::Microsoft::Terminal::Control::AutoDetectRunningCommand, L"Profile_AutoDetectRunningCommand", L"Content");
_InitializeCurrentBellSounds();
@@ -640,6 +641,170 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
BellStyle(currentStyle);
}
// ===================== NotifyOnInactiveOutput =====================
hstring ProfileViewModel::NotifyOnInactiveOutputPreview() const
{
using Ons = Control::OutputNotificationStyle;
const auto style = NotifyOnInactiveOutput();
if (WI_AreAllFlagsSet(style, Ons::Taskbar | Ons::Audible | Ons::Tab | Ons::Notification))
{
return RS_(L"Profile_OutputNotificationStyleAll/Content");
}
else if (style == static_cast<Ons>(0))
{
return RS_(L"Profile_OutputNotificationStyleNone/Content");
}
std::vector<hstring> resultList;
resultList.reserve(4);
if (WI_IsFlagSet(style, Ons::Taskbar))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleTaskbar/Content"));
}
if (WI_IsFlagSet(style, Ons::Audible))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleAudible/Content"));
}
if (WI_IsFlagSet(style, Ons::Tab))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleTab/Content"));
}
if (WI_IsFlagSet(style, Ons::Notification))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleNotification/Content"));
}
hstring result{};
for (auto&& entry : resultList)
{
if (result.empty())
{
result = entry;
}
else
{
result = result + L", " + entry;
}
}
return result;
}
bool ProfileViewModel::IsNotifyOnInactiveOutputFlagSet(const uint32_t flag)
{
return (WI_EnumValue(NotifyOnInactiveOutput()) & flag) == flag;
}
void ProfileViewModel::SetNotifyOnInactiveOutputTaskbar(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnInactiveOutput();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Taskbar, winrt::unbox_value<bool>(on));
NotifyOnInactiveOutput(currentStyle);
}
void ProfileViewModel::SetNotifyOnInactiveOutputAudible(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnInactiveOutput();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Audible, winrt::unbox_value<bool>(on));
NotifyOnInactiveOutput(currentStyle);
}
void ProfileViewModel::SetNotifyOnInactiveOutputTab(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnInactiveOutput();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Tab, winrt::unbox_value<bool>(on));
NotifyOnInactiveOutput(currentStyle);
}
void ProfileViewModel::SetNotifyOnInactiveOutputNotification(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnInactiveOutput();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Notification, winrt::unbox_value<bool>(on));
NotifyOnInactiveOutput(currentStyle);
}
// ===================== NotifyOnNextPrompt =====================
hstring ProfileViewModel::NotifyOnNextPromptPreview() const
{
using Ons = Control::OutputNotificationStyle;
const auto style = NotifyOnNextPrompt();
if (WI_AreAllFlagsSet(style, Ons::Taskbar | Ons::Audible | Ons::Tab | Ons::Notification))
{
return RS_(L"Profile_OutputNotificationStyleAll/Content");
}
else if (style == static_cast<Ons>(0))
{
return RS_(L"Profile_OutputNotificationStyleNone/Content");
}
std::vector<hstring> resultList;
resultList.reserve(4);
if (WI_IsFlagSet(style, Ons::Taskbar))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleTaskbar/Content"));
}
if (WI_IsFlagSet(style, Ons::Audible))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleAudible/Content"));
}
if (WI_IsFlagSet(style, Ons::Tab))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleTab/Content"));
}
if (WI_IsFlagSet(style, Ons::Notification))
{
resultList.emplace_back(RS_(L"Profile_OutputNotificationStyleNotification/Content"));
}
hstring result{};
for (auto&& entry : resultList)
{
if (result.empty())
{
result = entry;
}
else
{
result = result + L", " + entry;
}
}
return result;
}
bool ProfileViewModel::IsNotifyOnNextPromptFlagSet(const uint32_t flag)
{
return (WI_EnumValue(NotifyOnNextPrompt()) & flag) == flag;
}
void ProfileViewModel::SetNotifyOnNextPromptTaskbar(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Taskbar, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
void ProfileViewModel::SetNotifyOnNextPromptAudible(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Audible, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
void ProfileViewModel::SetNotifyOnNextPromptTab(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Tab, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
void ProfileViewModel::SetNotifyOnNextPromptNotification(winrt::Windows::Foundation::IReference<bool> on)
{
auto currentStyle = NotifyOnNextPrompt();
WI_UpdateFlag(currentStyle, Control::OutputNotificationStyle::Notification, winrt::unbox_value<bool>(on));
NotifyOnNextPrompt(currentStyle);
}
// Method Description:
// - Construct _CurrentBellSounds by importing the _inherited_ value from the model
// - Adds a PropertyChanged handler to each BellSoundViewModel to propagate changes to the model

View File

@@ -47,6 +47,22 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SetBellStyleWindow(winrt::Windows::Foundation::IReference<bool> on);
void SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on);
// notify on inactive output bits
hstring NotifyOnInactiveOutputPreview() const;
bool IsNotifyOnInactiveOutputFlagSet(const uint32_t flag);
void SetNotifyOnInactiveOutputTaskbar(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnInactiveOutputAudible(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnInactiveOutputTab(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnInactiveOutputNotification(winrt::Windows::Foundation::IReference<bool> on);
// notify on next prompt bits
hstring NotifyOnNextPromptPreview() const;
bool IsNotifyOnNextPromptFlagSet(const uint32_t flag);
void SetNotifyOnNextPromptTaskbar(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnNextPromptAudible(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnNextPromptTab(winrt::Windows::Foundation::IReference<bool> on);
void SetNotifyOnNextPromptNotification(winrt::Windows::Foundation::IReference<bool> on);
hstring BellSoundPreview();
void RequestAddBellSound(hstring path);
void RequestDeleteBellSound(const Editor::BellSoundViewModel& vm);
@@ -146,12 +162,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, RainbowSuggestions);
OBSERVABLE_PROJECTED_SETTING(_profile, PathTranslationStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, NotifyOnInactiveOutput);
OBSERVABLE_PROJECTED_SETTING(_profile, NotifyOnNextPrompt);
OBSERVABLE_PROJECTED_SETTING(_profile, AutoDetectRunningCommand);
WINRT_PROPERTY(bool, IsBaseLayer, false);
WINRT_PROPERTY(bool, FocusDeleteButton, false);
GETSET_BINDABLE_ENUM_SETTING(AntiAliasingMode, Microsoft::Terminal::Control::TextAntialiasingMode, AntialiasingMode);
GETSET_BINDABLE_ENUM_SETTING(CloseOnExitMode, Microsoft::Terminal::Settings::Model::CloseOnExitMode, CloseOnExit);
GETSET_BINDABLE_ENUM_SETTING(ScrollState, Microsoft::Terminal::Control::ScrollbarState, ScrollState);
GETSET_BINDABLE_ENUM_SETTING(PathTranslationStyle, Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle);
GETSET_BINDABLE_ENUM_SETTING(AutoDetectRunningCommand, Microsoft::Terminal::Control::AutoDetectRunningCommand, AutoDetectRunningCommand);
private:
Model::Profile _profile;

View File

@@ -50,6 +50,23 @@ namespace Microsoft.Terminal.Settings.Editor
void SetBellStyleWindow(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);
String NotifyOnInactiveOutputPreview { get; };
Boolean IsNotifyOnInactiveOutputFlagSet(UInt32 flag);
void SetNotifyOnInactiveOutputTaskbar(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnInactiveOutputAudible(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnInactiveOutputTab(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnInactiveOutputNotification(Windows.Foundation.IReference<Boolean> on);
String NotifyOnNextPromptPreview { get; };
Boolean IsNotifyOnNextPromptFlagSet(UInt32 flag);
void SetNotifyOnNextPromptTaskbar(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnNextPromptAudible(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnNextPromptTab(Windows.Foundation.IReference<Boolean> on);
void SetNotifyOnNextPromptNotification(Windows.Foundation.IReference<Boolean> on);
IInspectable CurrentAutoDetectRunningCommand;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> AutoDetectRunningCommandList { get; };
String BellSoundPreview { get; };
Windows.Foundation.Collections.IObservableVector<BellSoundViewModel> CurrentBellSounds { get; };
void RequestAddBellSound(String path);
@@ -140,5 +157,8 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RainbowSuggestions);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnInactiveOutput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnNextPrompt);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Control.AutoDetectRunningCommand, AutoDetectRunningCommand);
}
}

View File

@@ -196,6 +196,59 @@
</StackPanel>
</local:SettingContainer>
<!-- Notify On Inactive Output -->
<local:SettingContainer x:Name="NotifyOnInactiveOutput"
x:Uid="Profile_NotifyOnInactiveOutput"
ClearSettingValue="{x:Bind Profile.ClearNotifyOnInactiveOutput}"
CurrentValue="{x:Bind Profile.NotifyOnInactiveOutputPreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasNotifyOnInactiveOutput, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.NotifyOnInactiveOutputOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_OutputNotificationStyleTaskbar"
IsChecked="{x:Bind Profile.IsNotifyOnInactiveOutputFlagSet(1), BindBack=Profile.SetNotifyOnInactiveOutputTaskbar, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleAudible"
IsChecked="{x:Bind Profile.IsNotifyOnInactiveOutputFlagSet(2), BindBack=Profile.SetNotifyOnInactiveOutputAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleTab"
IsChecked="{x:Bind Profile.IsNotifyOnInactiveOutputFlagSet(4), BindBack=Profile.SetNotifyOnInactiveOutputTab, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleNotification"
IsChecked="{x:Bind Profile.IsNotifyOnInactiveOutputFlagSet(8), BindBack=Profile.SetNotifyOnInactiveOutputNotification, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Notify On Next Prompt -->
<local:SettingContainer x:Name="NotifyOnNextPrompt"
x:Uid="Profile_NotifyOnNextPrompt"
ClearSettingValue="{x:Bind Profile.ClearNotifyOnNextPrompt}"
CurrentValue="{x:Bind Profile.NotifyOnNextPromptPreview, Mode=OneWay}"
HasSettingValue="{x:Bind Profile.HasNotifyOnNextPrompt, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.NotifyOnNextPromptOverrideSource, Mode=OneWay}"
Style="{StaticResource ExpanderSettingContainerStyle}">
<StackPanel>
<CheckBox x:Uid="Profile_OutputNotificationStyleTaskbar"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(1), BindBack=Profile.SetNotifyOnNextPromptTaskbar, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleAudible"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(2), BindBack=Profile.SetNotifyOnNextPromptAudible, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleTab"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(4), BindBack=Profile.SetNotifyOnNextPromptTab, Mode=TwoWay}" />
<CheckBox x:Uid="Profile_OutputNotificationStyleNotification"
IsChecked="{x:Bind Profile.IsNotifyOnNextPromptFlagSet(8), BindBack=Profile.SetNotifyOnNextPromptNotification, Mode=TwoWay}" />
</StackPanel>
</local:SettingContainer>
<!-- Auto Detect Running Command -->
<local:SettingContainer x:Name="AutoDetectRunningCommand"
x:Uid="Profile_AutoDetectRunningCommand"
ClearSettingValue="{x:Bind Profile.ClearAutoDetectRunningCommand}"
HasSettingValue="{x:Bind Profile.HasAutoDetectRunningCommand, Mode=OneWay}"
SettingOverrideSource="{x:Bind Profile.AutoDetectRunningCommandOverrideSource, Mode=OneWay}">
<ComboBox AutomationProperties.AccessibilityView="Content"
ItemTemplate="{StaticResource EnumComboBoxTemplate}"
ItemsSource="{x:Bind Profile.AutoDetectRunningCommandList, Mode=OneWay}"
SelectedItem="{x:Bind Profile.CurrentAutoDetectRunningCommand, Mode=TwoWay}"
Style="{StaticResource ComboBoxSettingStyle}" />
</local:SettingContainer>
<!-- RightClickContextMenu -->
<local:SettingContainer x:Name="RightClickContextMenu"
x:Uid="Profile_RightClickContextMenu"

View File

@@ -2748,4 +2748,92 @@
<value>Type to filter icons</value>
<comment>Placeholder text for a text box to filter and select an icon.</comment>
</data>
<!-- OutputNotificationStyle shared checkbox labels -->
<data name="Profile_OutputNotificationStyleTaskbar.Content" xml:space="preserve">
<value>Flash taskbar</value>
<comment>An option to choose from for a notification style setting. When selected, the taskbar is flashed.</comment>
</data>
<data name="Profile_OutputNotificationStyleAudible.Content" xml:space="preserve">
<value>Audible</value>
<comment>An option to choose from for a notification style setting. When selected, an audible cue is played.</comment>
</data>
<data name="Profile_OutputNotificationStyleTab.Content" xml:space="preserve">
<value>Tab indicator</value>
<comment>An option to choose from for a notification style setting. When selected, an activity indicator is shown on the tab.</comment>
</data>
<data name="Profile_OutputNotificationStyleNotification.Content" xml:space="preserve">
<value>Desktop notification</value>
<comment>An option to choose from for a notification style setting. When selected, a desktop toast notification is sent.</comment>
</data>
<data name="Profile_OutputNotificationStyleAll/Content" xml:space="preserve">
<value>All</value>
<comment>An option label for notification style. Shown when all notification styles are enabled.</comment>
</data>
<data name="Profile_OutputNotificationStyleNone/Content" xml:space="preserve">
<value>None</value>
<comment>An option label for notification style. Shown when no notification styles are enabled.</comment>
</data>
<!-- NotifyOnInactiveOutput -->
<data name="Profile_NotifyOnInactiveOutput.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Notify on inactive output</value>
<comment>Name for a control to select how the app notifies the user when an inactive pane produces output.</comment>
</data>
<data name="Profile_NotifyOnInactiveOutput.Header" xml:space="preserve">
<value>Notify on inactive output</value>
<comment>Header for a control to select how the app notifies the user when an inactive pane produces output.</comment>
</data>
<data name="Profile_NotifyOnInactiveOutput.HelpText" xml:space="preserve">
<value>Controls how you are notified when a background pane produces new output.</value>
<comment>A description for what the "notify on inactive output" setting does.</comment>
</data>
<!-- NotifyOnNextPrompt -->
<data name="Profile_NotifyOnNextPrompt.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Notify on next prompt</value>
<comment>Name for a control to select how the app notifies the user when a command finishes and the shell returns to a prompt.</comment>
</data>
<data name="Profile_NotifyOnNextPrompt.Header" xml:space="preserve">
<value>Notify on next prompt</value>
<comment>Header for a control to select how the app notifies the user when a command finishes and the shell returns to a prompt.</comment>
</data>
<data name="Profile_NotifyOnNextPrompt.HelpText" xml:space="preserve">
<value>Controls how you are notified when a running command finishes and the shell returns to a prompt. Requires shell integration.</value>
<comment>A description for what the "notify on next prompt" setting does.</comment>
</data>
<!-- AutoDetectRunningCommand -->
<data name="Profile_AutoDetectRunningCommand.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Auto-detect running command</value>
<comment>Name for a control to select how the app detects and indicates a running command.</comment>
</data>
<data name="Profile_AutoDetectRunningCommand.Header" xml:space="preserve">
<value>Auto-detect running command</value>
<comment>Header for a control to select how the app detects and indicates a running command.</comment>
</data>
<data name="Profile_AutoDetectRunningCommand.HelpText" xml:space="preserve">
<value>Controls whether and how the terminal automatically shows progress while a command is running. Requires shell integration.</value>
<comment>A description for what the "auto-detect running command" setting does.</comment>
</data>
<data name="Profile_AutoDetectRunningCommand_Disabled.Content" xml:space="preserve">
<value>Disabled</value>
<comment>An option to choose from for the "auto-detect running command" setting. When selected, no auto-detection occurs.</comment>
</data>
<data name="Profile_AutoDetectRunningCommand_Automatic.Content" xml:space="preserve">
<value>Automatic</value>
<comment>An option to choose from for the "auto-detect running command" setting. When selected, an indeterminate progress ring is shown while a command is running.</comment>
</data>
<data name="Profile_AutoDetectRunningCommand_Progress.Content" xml:space="preserve">
<value>Progress</value>
<comment>An option to choose from for the "auto-detect running command" setting. When selected, the terminal attempts to detect progress percentage from command output.</comment>
</data>
<data name="Profile_AutoDetectRunningCommandDisabled.Content" xml:space="preserve">
<value>Disabled</value>
<comment>An option to choose from for the "auto-detect running command" setting. When selected, no auto-detection occurs.</comment>
</data>
<data name="Profile_AutoDetectRunningCommandAutomatic.Content" xml:space="preserve">
<value>Automatic</value>
<comment>An option to choose from for the "auto-detect running command" setting. When selected, an indeterminate progress ring is shown while a command is running.</comment>
</data>
<data name="Profile_AutoDetectRunningCommandProgress.Content" xml:space="preserve">
<value>Progress</value>
<comment>An option to choose from for the "auto-detect running command" setting. When selected, the terminal attempts to detect progress percentage from command output.</comment>
</data>
</root>

View File

@@ -53,6 +53,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
DEFINE_ENUM_MAP(Microsoft::Terminal::Settings::Model::IntenseStyle, IntenseTextStyle);
DEFINE_ENUM_MAP(Microsoft::Terminal::Core::AdjustTextMode, AdjustIndistinguishableColors);
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle);
DEFINE_ENUM_MAP(Microsoft::Terminal::Control::AutoDetectRunningCommand, AutoDetectRunningCommand);
// Actions
DEFINE_ENUM_MAP(Microsoft::Terminal::Settings::Model::ResizeDirection, ResizeDirection);

View File

@@ -51,6 +51,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Settings::Model::IntenseStyle> IntenseTextStyle();
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Core::AdjustTextMode> AdjustIndistinguishableColors();
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::PathTranslationStyle> PathTranslationStyle();
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Control::AutoDetectRunningCommand> AutoDetectRunningCommand();
// Actions
static winrt::Windows::Foundation::Collections::IMap<winrt::hstring, winrt::Microsoft::Terminal::Settings::Model::ResizeDirection> ResizeDirection();

View File

@@ -33,6 +33,7 @@ namespace Microsoft.Terminal.Settings.Model
static Windows.Foundation.Collections.IMap<String, UInt16> FontWeight { get; };
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.IntenseStyle> IntenseTextStyle { get; };
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.PathTranslationStyle> PathTranslationStyle { get; };
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Control.AutoDetectRunningCommand> AutoDetectRunningCommand { get; };
// Actions
static Windows.Foundation.Collections.IMap<String, Microsoft.Terminal.Settings.Model.ResizeDirection> ResizeDirection { get; };

View File

@@ -108,7 +108,10 @@ Author(s):
X(bool, AllowVtChecksumReport, "compatibility.allowDECRQCRA", false) \
X(bool, AllowVtClipboardWrite, "compatibility.allowOSC52", true) \
X(bool, AllowKeypadMode, "compatibility.allowDECNKM", false) \
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None)
X(Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, "pathTranslationStyle", Microsoft::Terminal::Control::PathTranslationStyle::None) \
X(Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnInactiveOutput, "notifyOnInactiveOutput", Microsoft::Terminal::Control::OutputNotificationStyle{0}) \
X(Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnNextPrompt, "notifyOnNextPrompt", Microsoft::Terminal::Control::OutputNotificationStyle{0}) \
X(Microsoft::Terminal::Control::AutoDetectRunningCommand, AutoDetectRunningCommand, "autoDetectRunningCommand", Microsoft::Terminal::Control::AutoDetectRunningCommand::Disabled)
// Intentionally omitted Profile settings:
// * Name

View File

@@ -94,5 +94,9 @@ namespace Microsoft.Terminal.Settings.Model
INHERITABLE_PROFILE_SETTING(Boolean, AllowVtClipboardWrite);
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.PathTranslationStyle, PathTranslationStyle);
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnInactiveOutput);
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.OutputNotificationStyle, NotifyOnNextPrompt);
INHERITABLE_PROFILE_SETTING(Microsoft.Terminal.Control.AutoDetectRunningCommand, AutoDetectRunningCommand);
}
}

View File

@@ -119,6 +119,46 @@ JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::BellStyle)
}
};
JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Control::OutputNotificationStyle)
{
static constexpr std::array<pair_type, 6> mappings = {
pair_type{ "none", AllClear },
pair_type{ "taskbar", ValueType::Taskbar },
pair_type{ "audible", ValueType::Audible },
pair_type{ "tab", ValueType::Tab },
pair_type{ "notification", ValueType::Notification },
pair_type{ "all", AllSet },
};
auto FromJson(const Json::Value& json)
{
if (json.isBool())
{
return json.asBool() ? ValueType::Tab : AllClear;
}
return BaseFlagMapper::FromJson(json);
}
bool CanConvert(const Json::Value& json)
{
return BaseFlagMapper::CanConvert(json) || json.isBool();
}
Json::Value ToJson(const ::winrt::Microsoft::Terminal::Control::OutputNotificationStyle& style)
{
return BaseFlagMapper::ToJson(style);
}
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Control::AutoDetectRunningCommand)
{
JSON_MAPPINGS(3) = {
pair_type{ "disabled", ValueType::Disabled },
pair_type{ "automatic", ValueType::Automatic },
pair_type{ "progress", ValueType::Progress },
};
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::ConvergedAlignment)
{
// reduce repetition

View File

@@ -87,4 +87,7 @@
X(bool, ShowMarks, false) \
X(winrt::Microsoft::Terminal::Control::CopyFormat, CopyFormatting, 0) \
X(bool, RightClickContextMenu, false) \
X(winrt::Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle::None)
X(winrt::Microsoft::Terminal::Control::PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle::None) \
X(winrt::Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnInactiveOutput, winrt::Microsoft::Terminal::Control::OutputNotificationStyle{0}) \
X(winrt::Microsoft::Terminal::Control::OutputNotificationStyle, NotifyOnNextPrompt, winrt::Microsoft::Terminal::Control::OutputNotificationStyle{0}) \
X(winrt::Microsoft::Terminal::Control::AutoDetectRunningCommand, AutoDetectRunningCommand, winrt::Microsoft::Terminal::Control::AutoDetectRunningCommand::Disabled)

View File

@@ -424,7 +424,7 @@ void ConhostInternalGetSet::NotifyBufferRotation(const int)
{
}
void ConhostInternalGetSet::NotifyShellIntegrationMark()
void ConhostInternalGetSet::NotifyShellIntegrationMark(ShellIntegrationMark /*mark*/)
{
// Not implemented for conhost - shell integration marks are a Terminal app feature.
}

View File

@@ -66,7 +66,7 @@ public:
bool IsVtInputEnabled() const override;
void NotifyBufferRotation(const int delta) override;
void NotifyShellIntegrationMark() override;
void NotifyShellIntegrationMark(ShellIntegrationMark mark) override;
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;

View File

@@ -85,7 +85,16 @@ namespace Microsoft::Console::VirtualTerminal
virtual bool ResizeWindow(const til::CoordType width, const til::CoordType height) = 0;
virtual void NotifyBufferRotation(const int delta) = 0;
virtual void NotifyShellIntegrationMark() = 0;
enum class ShellIntegrationMark
{
Prompt,
Command,
Output,
CommandFinished,
Other
};
virtual void NotifyShellIntegrationMark(ShellIntegrationMark mark) = 0;
virtual void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) = 0;

View File

@@ -3583,7 +3583,7 @@ void AdaptDispatch::DoConEmuAction(const std::wstring_view string)
else if (subParam == 12)
{
_pages.ActivePage().Buffer().StartCommand();
_api.NotifyShellIntegrationMark();
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Command);
}
}
@@ -3614,7 +3614,7 @@ void AdaptDispatch::DoITerm2Action(const std::wstring_view string)
if (action == L"SetMark")
{
_pages.ActivePage().Buffer().StartPrompt();
_api.NotifyShellIntegrationMark();
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Prompt);
}
}
@@ -3648,19 +3648,19 @@ void AdaptDispatch::DoFinalTermAction(const std::wstring_view string)
case L'A': // FTCS_PROMPT
{
_pages.ActivePage().Buffer().StartPrompt();
_api.NotifyShellIntegrationMark();
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Prompt);
break;
}
case L'B': // FTCS_COMMAND_START
{
_pages.ActivePage().Buffer().StartCommand();
_api.NotifyShellIntegrationMark();
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Command);
break;
}
case L'C': // FTCS_COMMAND_EXECUTED
{
_pages.ActivePage().Buffer().StartOutput();
_api.NotifyShellIntegrationMark();
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::Output);
break;
}
case L'D': // FTCS_COMMAND_FINISHED
@@ -3681,7 +3681,7 @@ void AdaptDispatch::DoFinalTermAction(const std::wstring_view string)
}
_pages.ActivePage().Buffer().EndCurrentCommand(error);
_api.NotifyShellIntegrationMark();
_api.NotifyShellIntegrationMark(ITerminalApi::ShellIntegrationMark::CommandFinished);
break;
}

View File

@@ -207,7 +207,7 @@ public:
Log::Comment(L"NotifyBufferRotation MOCK called...");
}
void NotifyShellIntegrationMark() override
void NotifyShellIntegrationMark(ShellIntegrationMark /*mark*/) override
{
Log::Comment(L"NotifyShellIntegrationMark MOCK called...");
}