mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Add Quick Fix UI and support for custom CommandNotFound OSC (#16848)
### `OSC 9001; CmdNotFound; <missingCmd>` Adds support for custom OSC "command not found" sequence `OSC 9001; CmdNotFound; <missingCmd>`. Upon receiving the "CmdNotFound" variant with the missing command payload, we send the missing command up to the Quick Fix menu and add it in as `winget install <missingCmd>`. ### Quick Fix UI The Quick Fix UI is a new UI surface that lives in the gutter (left padding) of your terminal. The button appears if quick fixes are available. When clicked, a list of suggestions appears in a flyout. If there is not enough space in the gutter, the button will be presented in a collapsed version that expands to a normal size upon hovering over it. The Quick Fix UI was implemented similar to the context menu. The UI itself lives in TermControl, but it can be populated by other layers (i.e. TermApp layer). Quick Fix suggestions are also automatically loaded into the Suggestions UI. If a quick fix is available and a screen reader is attached, we dispatch an announcement that quick fixes are available to notify the user that that's the case. Spec: #17005 #16599 ### Follow-ups - #17377: Add a key binding for quick fix - #17378: Use winget to search for packages using `missingCmd` --------- Co-authored-by: Dustin L. Howett <duhowett@microsoft.com> Co-authored-by: Dustin L. Howett <dustin@howett.net>
This commit is contained in:
parent
024837c50f
commit
6589957d4d
@ -1340,7 +1340,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// requires context from the control)
|
||||
// then get that here.
|
||||
const bool shouldGetContext = realArgs.UseCommandline() ||
|
||||
WI_IsFlagSet(source, SuggestionsSource::CommandHistory);
|
||||
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
|
||||
if (shouldGetContext)
|
||||
{
|
||||
if (const auto& control{ _GetActiveControl() })
|
||||
@ -1373,7 +1373,20 @@ namespace winrt::TerminalApp::implementation
|
||||
if (WI_IsFlagSet(source, SuggestionsSource::CommandHistory) &&
|
||||
context != nullptr)
|
||||
{
|
||||
const auto recentCommands = Command::HistoryToCommands(context.History(), currentCommandline, false);
|
||||
// \ue81c --> History icon
|
||||
const auto recentCommands = Command::HistoryToCommands(context.History(), currentCommandline, false, hstring{ L"\ue81c" });
|
||||
for (const auto& t : recentCommands)
|
||||
{
|
||||
commandsCollection.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (WI_IsFlagSet(source, SuggestionsSource::QuickFixes) &&
|
||||
context != nullptr &&
|
||||
context.QuickFixes() != nullptr)
|
||||
{
|
||||
// \ue74c --> OEM icon
|
||||
const auto recentCommands = Command::HistoryToCommands(context.QuickFixes(), hstring{ L"" }, false, hstring{ L"\ue74c" });
|
||||
for (const auto& t : recentCommands)
|
||||
{
|
||||
commandsCollection.push_back(t);
|
||||
|
||||
@ -1735,6 +1735,8 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
term.ShowWindowChanged({ get_weak(), &TerminalPage::_ShowWindowChangedHandler });
|
||||
|
||||
term.SearchMissingCommand({ get_weak(), &TerminalPage::_SearchMissingCommandHandler });
|
||||
|
||||
// Don't even register for the event if the feature is compiled off.
|
||||
if constexpr (Feature_ShellCompletions::IsEnabled())
|
||||
{
|
||||
@ -1753,6 +1755,12 @@ namespace winrt::TerminalApp::implementation
|
||||
page->_PopulateContextMenu(weakTerm.get(), sender.try_as<MUX::Controls::CommandBarFlyout>(), true);
|
||||
}
|
||||
});
|
||||
term.QuickFixMenu().Opening([weak = get_weak(), weakTerm](auto&& sender, auto&& /*args*/) {
|
||||
if (const auto& page{ weak.get() })
|
||||
{
|
||||
page->_PopulateQuickFixMenu(weakTerm.get(), sender.try_as<Controls::MenuFlyout>());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -2985,6 +2993,30 @@ namespace winrt::TerminalApp::implementation
|
||||
ShowWindowChanged.raise(*this, args);
|
||||
}
|
||||
|
||||
winrt::fire_and_forget TerminalPage::_SearchMissingCommandHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::SearchMissingCommandEventArgs args)
|
||||
{
|
||||
assert(!Dispatcher().HasThreadAccess());
|
||||
|
||||
if (!Feature_QuickFix::IsEnabled())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
std::vector<hstring> suggestions;
|
||||
suggestions.reserve(1);
|
||||
suggestions.emplace_back(fmt::format(FMT_COMPILE(L"winget install {}"), args.MissingCommand()));
|
||||
|
||||
co_await wil::resume_foreground(Dispatcher());
|
||||
|
||||
auto term = _GetActiveControl();
|
||||
if (!term)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
term.UpdateWinGetSuggestions(single_threaded_vector<hstring>(std::move(suggestions)));
|
||||
term.RefreshQuickFixMenu();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Paste text from the Windows Clipboard to the focused terminal
|
||||
void TerminalPage::_PasteText()
|
||||
@ -4905,6 +4937,53 @@ namespace winrt::TerminalApp::implementation
|
||||
makeItem(RS_(L"TabClose"), L"\xE711", ActionAndArgs{ ShortcutAction::CloseTab, CloseTabArgs{ _GetFocusedTabIndex().value() } });
|
||||
}
|
||||
|
||||
void TerminalPage::_PopulateQuickFixMenu(const TermControl& control,
|
||||
const Controls::MenuFlyout& menu)
|
||||
{
|
||||
if (!control || !menu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Helper lambda for dispatching a SendInput ActionAndArgs onto the
|
||||
// ShortcutActionDispatch. Used below to wire up each menu entry to the
|
||||
// respective action. Then clear the quick fix menu.
|
||||
auto weak = get_weak();
|
||||
auto makeCallback = [weak](const hstring& suggestion) {
|
||||
return [weak, suggestion](auto&&, auto&&) {
|
||||
if (auto page{ weak.get() })
|
||||
{
|
||||
const auto actionAndArgs = ActionAndArgs{ ShortcutAction::SendInput, SendInputArgs{ hstring{ L"\u0003" } + suggestion } };
|
||||
page->_actionDispatch->DoAction(actionAndArgs);
|
||||
if (auto ctrl = page->_GetActiveControl())
|
||||
{
|
||||
ctrl.ClearQuickFix();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Wire up each item to the action that should be performed. By actually
|
||||
// connecting these to actions, we ensure the implementation is
|
||||
// consistent. This also leaves room for customizing this menu with
|
||||
// actions in the future.
|
||||
|
||||
menu.Items().Clear();
|
||||
const auto quickFixes = control.CommandHistory().QuickFixes();
|
||||
for (const auto& qf : quickFixes)
|
||||
{
|
||||
MenuFlyoutItem item{};
|
||||
|
||||
auto iconElement = UI::IconPathConverter::IconWUX(L"\ue74c");
|
||||
Automation::AutomationProperties::SetAccessibilityView(iconElement, Automation::Peers::AccessibilityView::Raw);
|
||||
item.Icon(iconElement);
|
||||
|
||||
item.Text(qf);
|
||||
item.Click(makeCallback(qf));
|
||||
menu.Items().Append(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for our WindowProperties's PropertyChanged event. We'll use this
|
||||
// to pop the "Identify Window" toast when the user renames our window.
|
||||
winrt::fire_and_forget TerminalPage::_windowPropertyChanged(const IInspectable& /*sender*/,
|
||||
|
||||
@ -522,6 +522,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _OpenSuggestions(const Microsoft::Terminal::Control::TermControl& sender, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::Command> commandsCollection, winrt::TerminalApp::SuggestionsMode mode, winrt::hstring filterText);
|
||||
|
||||
void _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);
|
||||
winrt::fire_and_forget _SearchMissingCommandHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::SearchMissingCommandEventArgs args);
|
||||
|
||||
winrt::fire_and_forget _windowPropertyChanged(const IInspectable& sender, const winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
|
||||
|
||||
@ -539,6 +540,7 @@ namespace winrt::TerminalApp::implementation
|
||||
void _sendDraggedTabToWindow(const winrt::hstring& windowId, const uint32_t tabIndex, std::optional<til::point> dragPoint);
|
||||
|
||||
void _PopulateContextMenu(const Microsoft::Terminal::Control::TermControl& control, const Microsoft::UI::Xaml::Controls::CommandBarFlyout& sender, const bool withSelection);
|
||||
void _PopulateQuickFixMenu(const Microsoft::Terminal::Control::TermControl& control, const Windows::UI::Xaml::Controls::MenuFlyout& sender);
|
||||
winrt::Windows::UI::Xaml::Controls::MenuFlyout _CreateRunAsAdminFlyout(int profileIndex);
|
||||
|
||||
winrt::Microsoft::Terminal::Control::TermControl _senderOrActiveControl(const winrt::Windows::Foundation::IInspectable& sender);
|
||||
|
||||
@ -128,6 +128,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
auto pfnCompletionsChanged = [=](auto&& menuJson, auto&& replaceLength) { _terminalCompletionsChanged(menuJson, replaceLength); };
|
||||
_terminal->CompletionsChangedCallback(pfnCompletionsChanged);
|
||||
|
||||
auto pfnSearchMissingCommand = [this](auto&& PH1) { _terminalSearchMissingCommand(std::forward<decltype(PH1)>(PH1)); };
|
||||
_terminal->SetSearchMissingCommandCallback(pfnSearchMissingCommand);
|
||||
|
||||
auto pfnClearQuickFix = [this] { ClearQuickFix(); };
|
||||
_terminal->SetClearQuickFixCallback(pfnClearQuickFix);
|
||||
|
||||
// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
|
||||
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
|
||||
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
|
||||
@ -1627,6 +1633,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_midiAudio.PlayNote(reinterpret_cast<HWND>(_owningHwnd), noteNumber, velocity, std::chrono::duration_cast<std::chrono::milliseconds>(duration));
|
||||
}
|
||||
|
||||
void ControlCore::_terminalSearchMissingCommand(std::wstring_view missingCommand)
|
||||
{
|
||||
SearchMissingCommand.raise(*this, make<implementation::SearchMissingCommandEventArgs>(hstring{ missingCommand }));
|
||||
}
|
||||
|
||||
void ControlCore::ClearQuickFix()
|
||||
{
|
||||
_cachedQuickFixes = nullptr;
|
||||
RefreshQuickFixUI.raise(*this, nullptr);
|
||||
}
|
||||
|
||||
bool ControlCore::HasSelection() const
|
||||
{
|
||||
const auto lock = _terminal->LockForReading();
|
||||
@ -2297,9 +2314,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
auto context = winrt::make_self<CommandHistoryContext>(std::move(commands));
|
||||
context->CurrentCommandline(trimmedCurrentCommand);
|
||||
context->QuickFixes(_cachedQuickFixes);
|
||||
return *context;
|
||||
}
|
||||
|
||||
bool ControlCore::QuickFixesAvailable() const noexcept
|
||||
{
|
||||
return _cachedQuickFixes && _cachedQuickFixes.Size() > 0;
|
||||
}
|
||||
|
||||
void ControlCore::UpdateQuickFixes(const Windows::Foundation::Collections::IVector<hstring>& quickFixes)
|
||||
{
|
||||
_cachedQuickFixes = quickFixes;
|
||||
}
|
||||
|
||||
Core::Scheme ControlCore::ColorScheme() const noexcept
|
||||
{
|
||||
Core::Scheme s;
|
||||
|
||||
@ -68,8 +68,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
til::property<Windows::Foundation::Collections::IVector<winrt::hstring>> History;
|
||||
til::property<winrt::hstring> CurrentCommandline;
|
||||
til::property<Windows::Foundation::Collections::IVector<winrt::hstring>> QuickFixes;
|
||||
|
||||
CommandHistoryContext(std::vector<winrt::hstring>&& history)
|
||||
CommandHistoryContext(std::vector<winrt::hstring>&& history) :
|
||||
QuickFixes(winrt::single_threaded_vector<winrt::hstring>())
|
||||
{
|
||||
History(winrt::single_threaded_vector<winrt::hstring>(std::move(history)));
|
||||
}
|
||||
@ -153,6 +155,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void PersistToPath(const wchar_t* path) const;
|
||||
void RestoreFromPath(const wchar_t* path) const;
|
||||
|
||||
void ClearQuickFix();
|
||||
|
||||
#pragma region ICoreState
|
||||
const size_t TaskbarState() const noexcept;
|
||||
const size_t TaskbarProgress() const noexcept;
|
||||
@ -241,6 +245,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
hstring ReadEntireBuffer() const;
|
||||
Control::CommandHistoryContext CommandHistory() const;
|
||||
bool QuickFixesAvailable() const noexcept;
|
||||
void UpdateQuickFixes(const Windows::Foundation::Collections::IVector<hstring>& quickFixes);
|
||||
|
||||
void AdjustOpacity(const float opacity, const bool relative);
|
||||
|
||||
@ -285,6 +291,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
til::typed_event<IInspectable, Control::UpdateSelectionMarkersEventArgs> UpdateSelectionMarkers;
|
||||
til::typed_event<IInspectable, Control::OpenHyperlinkEventArgs> OpenHyperlink;
|
||||
til::typed_event<IInspectable, Control::CompletionsChangedEventArgs> CompletionsChanged;
|
||||
til::typed_event<IInspectable, Control::SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
til::typed_event<> RefreshQuickFixUI;
|
||||
|
||||
til::typed_event<> CloseTerminalRequested;
|
||||
til::typed_event<> RestartTerminalRequested;
|
||||
@ -354,6 +362,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
til::point _contextMenuBufferPosition{ 0, 0 };
|
||||
|
||||
Windows::Foundation::Collections::IVector<hstring> _cachedQuickFixes{ nullptr };
|
||||
|
||||
void _setupDispatcherAndCallbacks();
|
||||
|
||||
bool _setFontSizeUnderLock(float fontSize);
|
||||
@ -377,6 +387,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _terminalPlayMidiNote(const int noteNumber,
|
||||
const int velocity,
|
||||
const std::chrono::microseconds duration);
|
||||
void _terminalSearchMissingCommand(std::wstring_view missingCommand);
|
||||
|
||||
winrt::fire_and_forget _terminalCompletionsChanged(std::wstring_view menuJson, unsigned int replaceLength);
|
||||
|
||||
|
||||
@ -70,6 +70,7 @@ namespace Microsoft.Terminal.Control
|
||||
{
|
||||
IVector<String> History { get; };
|
||||
String CurrentCommandline { get; };
|
||||
IVector<String> QuickFixes { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass ControlCore : ICoreState
|
||||
@ -155,6 +156,7 @@ namespace Microsoft.Terminal.Control
|
||||
|
||||
String ReadEntireBuffer();
|
||||
CommandHistoryContext CommandHistory();
|
||||
Boolean QuickFixesAvailable { get; };
|
||||
|
||||
void AdjustOpacity(Single Opacity, Boolean relative);
|
||||
void WindowVisibilityChanged(Boolean showOrHide);
|
||||
@ -166,6 +168,8 @@ namespace Microsoft.Terminal.Control
|
||||
Boolean ShouldShowSelectCommand();
|
||||
Boolean ShouldShowSelectOutput();
|
||||
|
||||
void ClearQuickFix();
|
||||
|
||||
// These events are called from some background thread
|
||||
event Windows.Foundation.TypedEventHandler<Object, TitleChangedEventArgs> TitleChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
|
||||
@ -174,6 +178,8 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> TaskbarProgressChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RendererEnteredErrorState;
|
||||
event Windows.Foundation.TypedEventHandler<Object, ShowWindowArgs> ShowWindowChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RefreshQuickFixUI;
|
||||
|
||||
// These events are always called from the UI thread (bugs aside)
|
||||
event Windows.Foundation.TypedEventHandler<Object, FontSizeChangedArgs> FontSizeChanged;
|
||||
|
||||
@ -18,3 +18,4 @@
|
||||
#include "KeySentEventArgs.g.cpp"
|
||||
#include "CharSentEventArgs.g.cpp"
|
||||
#include "StringSentEventArgs.g.cpp"
|
||||
#include "SearchMissingCommandEventArgs.g.cpp"
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "KeySentEventArgs.g.h"
|
||||
#include "CharSentEventArgs.g.h"
|
||||
#include "StringSentEventArgs.g.h"
|
||||
#include "SearchMissingCommandEventArgs.g.h"
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
@ -211,6 +212,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
WINRT_PROPERTY(winrt::hstring, Text);
|
||||
};
|
||||
|
||||
struct SearchMissingCommandEventArgs : public SearchMissingCommandEventArgsT<SearchMissingCommandEventArgs>
|
||||
{
|
||||
public:
|
||||
SearchMissingCommandEventArgs(const winrt::hstring& missingCommand) :
|
||||
MissingCommand(missingCommand) {}
|
||||
|
||||
til::property<winrt::hstring> MissingCommand;
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::Microsoft::Terminal::Control::factory_implementation
|
||||
|
||||
@ -126,4 +126,9 @@ namespace Microsoft.Terminal.Control
|
||||
{
|
||||
String Text { get; };
|
||||
}
|
||||
|
||||
runtimeclass SearchMissingCommandEventArgs
|
||||
{
|
||||
String MissingCommand { get; };
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,6 +301,12 @@ Please either install the missing font or choose another one.</value>
|
||||
<value>Select output</value>
|
||||
<comment>The tooltip for a button for selecting all of a command's output</comment>
|
||||
</data>
|
||||
<data name="QuickFixButton.ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Quick fix</value>
|
||||
</data>
|
||||
<data name="QuickFixButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Quick fix</value>
|
||||
</data>
|
||||
<data name="SessionRestoreMessage" xml:space="preserve">
|
||||
<value>Restored</value>
|
||||
<comment>"Restored" as in "This content was restored"</comment>
|
||||
@ -317,6 +323,13 @@ Please either install the missing font or choose another one.</value>
|
||||
<value>invalid</value>
|
||||
<comment>This brief message is displayed when a regular expression is invalid.</comment>
|
||||
</data>
|
||||
<data name="QuickFixAvailable" xml:space="preserve">
|
||||
<value>Quick fix available</value>
|
||||
<comment>"Quick fix" is referencing the same feature as "QuickFixButton.ToolTipService.ToolTip".</comment>
|
||||
</data>
|
||||
<data name="QuickFixMenu.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Quick fix</value>
|
||||
</data>
|
||||
<data name="PreviewTextAnnouncement" xml:space="preserve">
|
||||
<value>Suggested input: {0}</value>
|
||||
<comment>{Locked="{0}"} {0} will be replaced with a string of input that is suggested for the user to input</comment>
|
||||
|
||||
@ -40,6 +40,9 @@ constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(
|
||||
// The minimum delay between emitting warning bells
|
||||
constexpr const auto TerminalWarningBellInterval = std::chrono::milliseconds(1000);
|
||||
|
||||
constexpr std::wstring_view StateNormal{ L"Normal" };
|
||||
constexpr std::wstring_view StateCollapsed{ L"Collapsed" };
|
||||
|
||||
DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::CopyFormat);
|
||||
DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::MouseButtonState);
|
||||
|
||||
@ -220,9 +223,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_revokers.CloseTerminalRequested = _core.CloseTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCloseTerminalRequested });
|
||||
_revokers.CompletionsChanged = _core.CompletionsChanged(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleCompletionsChanged });
|
||||
_revokers.RestartTerminalRequested = _core.RestartTerminalRequested(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleRestartTerminalRequested });
|
||||
_revokers.SearchMissingCommand = _core.SearchMissingCommand(winrt::auto_revoke, { get_weak(), &TermControl::_bubbleSearchMissingCommand });
|
||||
|
||||
_revokers.PasteFromClipboard = _interactivity.PasteFromClipboard(winrt::auto_revoke, { get_weak(), &TermControl::_bubblePasteFromClipboard });
|
||||
|
||||
_revokers.RefreshQuickFixUI = _core.RefreshQuickFixUI(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
RefreshQuickFixMenu();
|
||||
});
|
||||
|
||||
// Initialize the terminal only once the swapchainpanel is loaded - that
|
||||
// way, we'll be able to query the real pixel size it got on layout
|
||||
_layoutUpdatedRevoker = SwapChainPanel().LayoutUpdated(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) {
|
||||
@ -334,6 +342,22 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
});
|
||||
}
|
||||
|
||||
void TermControl::_QuickFixButton_PointerEntered(const IInspectable& /*sender*/, const PointerRoutedEventArgs& /*e*/)
|
||||
{
|
||||
if (!_IsClosing() && _quickFixButtonCollapsible)
|
||||
{
|
||||
VisualStateManager::GoToState(*this, StateNormal, false);
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::_QuickFixButton_PointerExited(const IInspectable& /*sender*/, const PointerRoutedEventArgs& /*e*/)
|
||||
{
|
||||
if (!_IsClosing() && _quickFixButtonCollapsible)
|
||||
{
|
||||
VisualStateManager::GoToState(*this, StateCollapsed, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Function Description:
|
||||
// - Static helper for building a new TermControl from an already existing
|
||||
// content. We'll attach the existing swapchain to this new control's
|
||||
@ -832,6 +856,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// When we hot reload the settings, the core will send us a scrollbar
|
||||
// update. If we enabled scrollbar marks, then great, when we handle
|
||||
// that message, we'll redraw them.
|
||||
|
||||
// update the position of the quick fix menu (in case we changed the padding)
|
||||
RefreshQuickFixMenu();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@ -2347,6 +2374,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
{
|
||||
_updateSelectionMarkers(nullptr, winrt::make<UpdateSelectionMarkersEventArgs>(false));
|
||||
}
|
||||
|
||||
RefreshQuickFixMenu();
|
||||
}
|
||||
|
||||
hstring TermControl::Title()
|
||||
@ -3506,7 +3535,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
const Control::FontSizeChangedArgs& args)
|
||||
{
|
||||
// scale the selection markers to be the size of a cell
|
||||
auto scaleMarker = [args, dpiScale{ SwapChainPanel().CompositionScaleX() }](const Windows::UI::Xaml::Shapes::Path& shape) {
|
||||
const auto dpiScale = SwapChainPanel().CompositionScaleX();
|
||||
auto scaleMarker = [&args, &dpiScale](const Windows::UI::Xaml::Shapes::Path& shape) {
|
||||
// The selection markers were designed to be 5x14 in size,
|
||||
// so use those dimensions below for the scaling
|
||||
const auto scaleX = args.Width() / 5.0 / dpiScale;
|
||||
@ -3522,6 +3552,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
};
|
||||
scaleMarker(SelectionStartMarker());
|
||||
scaleMarker(SelectionEndMarker());
|
||||
|
||||
if (Feature_QuickFix::IsEnabled())
|
||||
{
|
||||
auto quickFixBtn = FindName(L"QuickFixButton").as<Controls::Button>();
|
||||
quickFixBtn.Height(args.Height() / dpiScale);
|
||||
QuickFixIcon().FontSize(static_cast<double>(args.Width() / dpiScale));
|
||||
RefreshQuickFixMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::_coreRaisedNotice(const IInspectable& /*sender*/,
|
||||
@ -3590,6 +3628,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
return _core.CommandHistory();
|
||||
}
|
||||
|
||||
void TermControl::UpdateWinGetSuggestions(Windows::Foundation::Collections::IVector<hstring> suggestions)
|
||||
{
|
||||
get_self<ControlCore>(_core)->UpdateQuickFixes(suggestions);
|
||||
}
|
||||
|
||||
Core::Scheme TermControl::ColorScheme() const noexcept
|
||||
{
|
||||
return _core.ColorScheme();
|
||||
@ -3829,6 +3872,86 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
_showContextMenuAt(_toControlOrigin(cursorPos));
|
||||
}
|
||||
|
||||
double TermControl::QuickFixButtonWidth()
|
||||
{
|
||||
const auto leftPadding = GetPadding().Left;
|
||||
if (_quickFixButtonCollapsible)
|
||||
{
|
||||
const auto cellWidth = CharacterDimensions().Width;
|
||||
if (leftPadding == 0)
|
||||
{
|
||||
return cellWidth;
|
||||
}
|
||||
return leftPadding + (cellWidth / 2.0);
|
||||
}
|
||||
return leftPadding;
|
||||
}
|
||||
|
||||
double TermControl::QuickFixButtonCollapsedWidth()
|
||||
{
|
||||
return std::max(CharacterDimensions().Width * 2.0 / 3.0, GetPadding().Left);
|
||||
}
|
||||
|
||||
void TermControl::RefreshQuickFixMenu()
|
||||
{
|
||||
if (!Feature_QuickFix::IsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto quickFixBtn = FindName(L"QuickFixButton").as<Controls::Button>();
|
||||
if (!_core.QuickFixesAvailable())
|
||||
{
|
||||
quickFixBtn.Visibility(Visibility::Collapsed);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the gutter is narrow, display the collapsed version
|
||||
const auto& termPadding = GetPadding();
|
||||
|
||||
// Make sure to update _quickFixButtonCollapsible and QuickFix button widths BEFORE updating the VisualState
|
||||
_quickFixButtonCollapsible = termPadding.Left < CharacterDimensions().Width;
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"QuickFixButtonWidth" });
|
||||
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"QuickFixButtonCollapsedWidth" });
|
||||
VisualStateManager::GoToState(*this, !_quickFixButtonCollapsible ? StateNormal : StateCollapsed, false);
|
||||
|
||||
const auto rd = get_self<ControlCore>(_core)->GetRenderData();
|
||||
rd->LockConsole();
|
||||
const auto viewportBufferPosition = rd->GetViewport();
|
||||
const auto cursorBufferPosition = rd->GetCursorPosition();
|
||||
rd->UnlockConsole();
|
||||
if (cursorBufferPosition.y < viewportBufferPosition.Top() || cursorBufferPosition.y > viewportBufferPosition.BottomExclusive())
|
||||
{
|
||||
quickFixBtn.Visibility(Visibility::Collapsed);
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the button in the gutter
|
||||
const auto& cursorPosInDips = CursorPositionInDips();
|
||||
Controls::Canvas::SetLeft(quickFixBtn, -termPadding.Left);
|
||||
Controls::Canvas::SetTop(quickFixBtn, cursorPosInDips.Y - termPadding.Top);
|
||||
quickFixBtn.Visibility(Visibility::Visible);
|
||||
|
||||
if (auto automationPeer{ FrameworkElementAutomationPeer::FromElement(*this) })
|
||||
{
|
||||
automationPeer.RaiseNotificationEvent(
|
||||
AutomationNotificationKind::ItemAdded,
|
||||
AutomationNotificationProcessing::ImportantMostRecent,
|
||||
RS_(L"QuickFixAvailable"),
|
||||
L"QuickFixAvailableAnnouncement" /* unique name for this group of notifications */);
|
||||
}
|
||||
}
|
||||
|
||||
void TermControl::_bubbleSearchMissingCommand(const IInspectable& /*sender*/, const Control::SearchMissingCommandEventArgs& args)
|
||||
{
|
||||
SearchMissingCommand.raise(*this, args);
|
||||
}
|
||||
|
||||
void TermControl::ClearQuickFix()
|
||||
{
|
||||
_core.ClearQuickFix();
|
||||
}
|
||||
|
||||
void TermControl::_PasteCommandHandler(const IInspectable& /*sender*/,
|
||||
const IInspectable& /*args*/)
|
||||
{
|
||||
|
||||
@ -76,6 +76,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void PreviewInput(const winrt::hstring& text);
|
||||
|
||||
Windows::Foundation::Point CursorPositionInDips();
|
||||
double QuickFixButtonWidth();
|
||||
double QuickFixButtonCollapsedWidth();
|
||||
|
||||
void WindowVisibilityChanged(const bool showOrHide);
|
||||
|
||||
@ -168,6 +170,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
hstring ReadEntireBuffer() const;
|
||||
Control::CommandHistoryContext CommandHistory() const;
|
||||
void UpdateWinGetSuggestions(Windows::Foundation::Collections::IVector<hstring> suggestions);
|
||||
|
||||
winrt::Microsoft::Terminal::Core::Scheme ColorScheme() const noexcept;
|
||||
void ColorScheme(const winrt::Microsoft::Terminal::Core::Scheme& scheme) const noexcept;
|
||||
@ -179,6 +182,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void RawWriteString(const winrt::hstring& text);
|
||||
|
||||
void ShowContextMenu();
|
||||
void RefreshQuickFixMenu();
|
||||
void ClearQuickFix();
|
||||
|
||||
void Detach();
|
||||
|
||||
@ -203,17 +208,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
til::typed_event<IInspectable, Control::KeySentEventArgs> KeySent;
|
||||
til::typed_event<IInspectable, Control::CharSentEventArgs> CharSent;
|
||||
til::typed_event<IInspectable, Control::StringSentEventArgs> StringSent;
|
||||
til::typed_event<IInspectable, Control::SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
|
||||
// UNDER NO CIRCUMSTANCES SHOULD YOU ADD A (PROJECTED_)FORWARDED_TYPED_EVENT HERE
|
||||
// Those attach the handler to the core directly, and will explode if
|
||||
// the core ever gets detached & reattached to another window.
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(CompletionsChanged, IInspectable, Control::CompletionsChangedEventArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(TitleChanged, IInspectable, Control::TitleChangedEventArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(TabColorChanged, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(ConnectionStateChanged, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(CloseTerminalRequested, IInspectable, IInspectable);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(CompletionsChanged, IInspectable, Control::CompletionsChangedEventArgs);
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(RestartTerminalRequested, IInspectable, IInspectable);
|
||||
|
||||
BUBBLED_FORWARDED_TYPED_EVENT(PasteFromClipboard, IInspectable, Control::PasteFromClipboardEventArgs);
|
||||
@ -243,6 +249,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
bool _closing{ false };
|
||||
bool _focused{ false };
|
||||
bool _initializedTerminal{ false };
|
||||
bool _quickFixButtonCollapsible{ false };
|
||||
bool _quickFixesAvailable{ false };
|
||||
|
||||
std::shared_ptr<ThrottledFuncLeading> _playWarningBell;
|
||||
|
||||
@ -333,6 +341,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _MouseWheelHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _ScrollbarChangeHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs& e);
|
||||
|
||||
void _QuickFixButton_PointerEntered(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
void _QuickFixButton_PointerExited(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::PointerRoutedEventArgs& e);
|
||||
|
||||
void _GotFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
void _LostFocusHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
|
||||
|
||||
@ -395,6 +406,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
void _contextMenuHandler(IInspectable sender, Control::ContextMenuRequestedEventArgs args);
|
||||
void _showContextMenuAt(const til::point& controlRelativePos);
|
||||
|
||||
void _bubbleSearchMissingCommand(const IInspectable& sender, const Control::SearchMissingCommandEventArgs& args);
|
||||
|
||||
void _PasteCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
void _CopyCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
void _SearchCommandHandler(const IInspectable& sender, const IInspectable& args);
|
||||
@ -424,6 +437,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
Control::ControlCore::CloseTerminalRequested_revoker CloseTerminalRequested;
|
||||
Control::ControlCore::CompletionsChanged_revoker CompletionsChanged;
|
||||
Control::ControlCore::RestartTerminalRequested_revoker RestartTerminalRequested;
|
||||
Control::ControlCore::SearchMissingCommand_revoker SearchMissingCommand;
|
||||
Control::ControlCore::RefreshQuickFixUI_revoker RefreshQuickFixUI;
|
||||
|
||||
// These are set up in _InitializeTerminal
|
||||
Control::ControlCore::RendererWarning_revoker RendererWarning;
|
||||
|
||||
@ -69,10 +69,12 @@ namespace Microsoft.Terminal.Control
|
||||
event Windows.Foundation.TypedEventHandler<Object, KeySentEventArgs> KeySent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, CharSentEventArgs> CharSent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, StringSentEventArgs> StringSent;
|
||||
event Windows.Foundation.TypedEventHandler<Object, SearchMissingCommandEventArgs> SearchMissingCommand;
|
||||
|
||||
|
||||
Microsoft.UI.Xaml.Controls.CommandBarFlyout ContextMenu { get; };
|
||||
Microsoft.UI.Xaml.Controls.CommandBarFlyout SelectionContextMenu { get; };
|
||||
Windows.UI.Xaml.Controls.MenuFlyout QuickFixMenu { get; };
|
||||
|
||||
event Windows.Foundation.TypedEventHandler<TermControl, Windows.UI.Xaml.RoutedEventArgs> Initialized;
|
||||
// This is an event handler forwarder for the underlying connection.
|
||||
@ -125,6 +127,7 @@ namespace Microsoft.Terminal.Control
|
||||
|
||||
String ReadEntireBuffer();
|
||||
CommandHistoryContext CommandHistory();
|
||||
void UpdateWinGetSuggestions(Windows.Foundation.Collections.IVector<String> suggestions);
|
||||
|
||||
void AdjustOpacity(Single Opacity, Boolean relative);
|
||||
void PreviewInput(String text);
|
||||
@ -142,8 +145,12 @@ namespace Microsoft.Terminal.Control
|
||||
void ColorSelection(SelectionColor fg, SelectionColor bg, Microsoft.Terminal.Core.MatchMode matchMode);
|
||||
|
||||
Windows.Foundation.Point CursorPositionInDips { get; };
|
||||
Double QuickFixButtonWidth { get; };
|
||||
Double QuickFixButtonCollapsedWidth { get; };
|
||||
|
||||
void ShowContextMenu();
|
||||
void RefreshQuickFixMenu();
|
||||
void ClearQuickFix();
|
||||
|
||||
void Detach();
|
||||
}
|
||||
|
||||
@ -1279,6 +1279,32 @@
|
||||
</ToolTip>
|
||||
</ToolTipService.ToolTip>
|
||||
</Border>
|
||||
|
||||
<Button x:Name="QuickFixButton"
|
||||
x:Uid="QuickFixButton"
|
||||
Width="{x:Bind QuickFixButtonWidth, Mode=OneWay}"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
x:Load="False"
|
||||
AllowFocusOnInteraction="False"
|
||||
CornerRadius="0,5,5,0"
|
||||
PointerEntered="_QuickFixButton_PointerEntered"
|
||||
PointerExited="_QuickFixButton_PointerExited"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
Visibility="Collapsed">
|
||||
<Button.Content>
|
||||
<FontIcon x:Name="QuickFixIcon"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Glyph="" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<MenuFlyout x:Name="QuickFixMenu"
|
||||
x:Uid="QuickFixMenu" />
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</Canvas>
|
||||
|
||||
<Canvas x:Name="SelectionCanvas"
|
||||
@ -1353,6 +1379,18 @@
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="QuickFixButtonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Collapsed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="QuickFixButton.Width" Value="{x:Bind QuickFixButtonCollapsedWidth, Mode=OneWay}" />
|
||||
<Setter Target="QuickFixButton.Background" Value="{ThemeResource SystemAccentColor}" />
|
||||
<Setter Target="QuickFixIcon.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@ -700,34 +700,44 @@ TerminalInput::OutputType Terminal::SendCharEvent(const wchar_t ch, const WORD s
|
||||
vkey = _VirtualKeyFromCharacter(ch);
|
||||
}
|
||||
|
||||
// GH#1527: When the user has auto mark prompts enabled, we're going to try
|
||||
// and heuristically detect if this was the line the prompt was on.
|
||||
// * If the key was an Enter keypress (Terminal.app also marks ^C keypresses
|
||||
// as prompts. That's omitted for now.)
|
||||
// * AND we're not in the alt buffer
|
||||
//
|
||||
// Then treat this line like it's a prompt mark.
|
||||
if (_autoMarkPrompts && vkey == VK_RETURN && !_inAltBuffer())
|
||||
if (vkey == VK_RETURN && !_inAltBuffer())
|
||||
{
|
||||
// We need to be a little tricky here, to try and support folks that are
|
||||
// auto-marking prompts, but don't necessarily have the rest of shell
|
||||
// integration enabled.
|
||||
//
|
||||
// We'll set the current attributes to Output, so that the output after
|
||||
// here is marked as the command output. But we also need to make sure
|
||||
// that a mark was started.
|
||||
// We can't just check if the current row has a mark - there could be a
|
||||
// multiline prompt.
|
||||
//
|
||||
// (TextBuffer::_createPromptMarkIfNeeded does that work for us)
|
||||
|
||||
const bool createdMark = _activeBuffer().StartOutput();
|
||||
if (createdMark)
|
||||
// Treat VK_RETURN as a new prompt,
|
||||
// so we should clear the quick fix UI if it's visible.
|
||||
if (_pfnClearQuickFix)
|
||||
{
|
||||
_activeBuffer().ManuallyMarkRowAsPrompt(_activeBuffer().GetCursor().GetPosition().y);
|
||||
_pfnClearQuickFix();
|
||||
}
|
||||
|
||||
// This changed the scrollbar marks - raise a notification to update them
|
||||
_NotifyScrollEvent();
|
||||
// GH#1527: When the user has auto mark prompts enabled, we're going to try
|
||||
// and heuristically detect if this was the line the prompt was on.
|
||||
// * If the key was an Enter keypress (Terminal.app also marks ^C keypresses
|
||||
// as prompts. That's omitted for now.)
|
||||
// * AND we're not in the alt buffer
|
||||
//
|
||||
// Then treat this line like it's a prompt mark.
|
||||
if (_autoMarkPrompts)
|
||||
{
|
||||
// We need to be a little tricky here, to try and support folks that are
|
||||
// auto-marking prompts, but don't necessarily have the rest of shell
|
||||
// integration enabled.
|
||||
//
|
||||
// We'll set the current attributes to Output, so that the output after
|
||||
// here is marked as the command output. But we also need to make sure
|
||||
// that a mark was started.
|
||||
// We can't just check if the current row has a mark - there could be a
|
||||
// multiline prompt.
|
||||
//
|
||||
// (TextBuffer::_createPromptMarkIfNeeded does that work for us)
|
||||
|
||||
const bool createdMark = _activeBuffer().StartOutput();
|
||||
if (createdMark)
|
||||
{
|
||||
_activeBuffer().ManuallyMarkRowAsPrompt(_activeBuffer().GetCursor().GetPosition().y);
|
||||
|
||||
// This changed the scrollbar marks - raise a notification to update them
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1228,6 +1238,16 @@ void Microsoft::Terminal::Core::Terminal::CompletionsChangedCallback(std::functi
|
||||
_pfnCompletionsChanged.swap(pfn);
|
||||
}
|
||||
|
||||
void Microsoft::Terminal::Core::Terminal::SetSearchMissingCommandCallback(std::function<void(std::wstring_view)> pfn) noexcept
|
||||
{
|
||||
_pfnSearchMissingCommand.swap(pfn);
|
||||
}
|
||||
|
||||
void Microsoft::Terminal::Core::Terminal::SetClearQuickFixCallback(std::function<void()> pfn) noexcept
|
||||
{
|
||||
_pfnClearQuickFix.swap(pfn);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Stores the search highlighted regions in the terminal
|
||||
void Terminal::SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept
|
||||
|
||||
@ -157,6 +157,8 @@ public:
|
||||
|
||||
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
|
||||
|
||||
void SearchMissingCommand(const std::wstring_view command) override;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void ClearMark();
|
||||
@ -229,6 +231,8 @@ public:
|
||||
void SetShowWindowCallback(std::function<void(bool)> pfn) noexcept;
|
||||
void SetPlayMidiNoteCallback(std::function<void(const int, const int, const std::chrono::microseconds)> pfn) noexcept;
|
||||
void CompletionsChangedCallback(std::function<void(std::wstring_view, unsigned int)> pfn) noexcept;
|
||||
void SetSearchMissingCommandCallback(std::function<void(std::wstring_view)> pfn) noexcept;
|
||||
void SetClearQuickFixCallback(std::function<void()> pfn) noexcept;
|
||||
void SetSearchHighlights(const std::vector<til::point_span>& highlights) noexcept;
|
||||
void SetSearchHighlightFocused(const size_t focusedIdx);
|
||||
|
||||
@ -339,6 +343,8 @@ private:
|
||||
std::function<void(bool)> _pfnShowWindowChanged;
|
||||
std::function<void(const int, const int, const std::chrono::microseconds)> _pfnPlayMidiNote;
|
||||
std::function<void(std::wstring_view, unsigned int)> _pfnCompletionsChanged;
|
||||
std::function<void(std::wstring_view)> _pfnSearchMissingCommand;
|
||||
std::function<void()> _pfnClearQuickFix;
|
||||
|
||||
RenderSettings _renderSettings;
|
||||
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
|
||||
|
||||
@ -333,6 +333,14 @@ void Terminal::InvokeCompletions(std::wstring_view menuJson, unsigned int replac
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::SearchMissingCommand(const std::wstring_view command)
|
||||
{
|
||||
if (_pfnSearchMissingCommand)
|
||||
{
|
||||
_pfnSearchMissingCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
void Terminal::NotifyBufferRotation(const int delta)
|
||||
{
|
||||
// Update our selection, so it doesn't move as the buffer is cycled
|
||||
|
||||
@ -928,6 +928,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::factory_implementation
|
||||
BASIC_FACTORY(SetTabColorArgs);
|
||||
BASIC_FACTORY(RenameTabArgs);
|
||||
BASIC_FACTORY(SwapPaneArgs);
|
||||
BASIC_FACTORY(SendInputArgs);
|
||||
BASIC_FACTORY(SplitPaneArgs);
|
||||
BASIC_FACTORY(SetFocusModeArgs);
|
||||
BASIC_FACTORY(SetFullScreenArgs);
|
||||
|
||||
@ -119,6 +119,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
Tasks = 0x1,
|
||||
CommandHistory = 0x2,
|
||||
DirectoryHistory = 0x4,
|
||||
QuickFixes = 0x8,
|
||||
All = 0xffffffff,
|
||||
};
|
||||
|
||||
@ -225,6 +226,8 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
|
||||
[default_interface] runtimeclass SendInputArgs : IActionArgs
|
||||
{
|
||||
SendInputArgs(String input);
|
||||
|
||||
String Input { get; };
|
||||
};
|
||||
|
||||
|
||||
@ -673,7 +673,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
// the command will be run as a directory change instead.
|
||||
IVector<Model::Command> Command::HistoryToCommands(IVector<winrt::hstring> history,
|
||||
winrt::hstring currentCommandline,
|
||||
bool directories)
|
||||
bool directories,
|
||||
winrt::hstring iconPath)
|
||||
{
|
||||
std::wstring cdText = directories ? L"cd " : L"";
|
||||
auto result = std::vector<Model::Command>();
|
||||
@ -705,9 +706,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
auto command = winrt::make_self<Command>();
|
||||
command->_ActionAndArgs = actionAndArgs;
|
||||
command->_name = winrt::hstring{ line };
|
||||
command->_iconPath = directories ?
|
||||
L"\ue8da" : // OpenLocal (a folder with an arrow pointing up)
|
||||
L"\ue81c"; // History icon
|
||||
command->_iconPath = iconPath;
|
||||
result.push_back(*command);
|
||||
foundCommands[line] = true;
|
||||
}
|
||||
|
||||
@ -79,7 +79,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
static Windows::Foundation::Collections::IVector<Model::Command> ParsePowerShellMenuComplete(winrt::hstring json, int32_t replaceLength);
|
||||
static Windows::Foundation::Collections::IVector<Model::Command> HistoryToCommands(Windows::Foundation::Collections::IVector<winrt::hstring> history,
|
||||
winrt::hstring currentCommandline,
|
||||
bool directories);
|
||||
bool directories,
|
||||
hstring iconPath);
|
||||
|
||||
WINRT_PROPERTY(ExpandCommandType, IterateOn, ExpandCommandType::None);
|
||||
WINRT_PROPERTY(Model::ActionAndArgs, ActionAndArgs);
|
||||
|
||||
@ -48,7 +48,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
Windows.Foundation.Collections.IMapView<String, Command> NestedCommands { get; };
|
||||
|
||||
static IVector<Command> ParsePowerShellMenuComplete(String json, Int32 replaceLength);
|
||||
static IVector<Command> HistoryToCommands(IVector<String> commandHistory, String commandline, Boolean directories);
|
||||
static IVector<Command> HistoryToCommands(IVector<String> commandHistory, String commandline, Boolean directories, String iconPath);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,11 +501,12 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FindMatchDirecti
|
||||
|
||||
JSON_FLAG_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::SuggestionsSource)
|
||||
{
|
||||
static constexpr std::array<pair_type, 5> mappings = {
|
||||
static constexpr std::array<pair_type, 6> mappings = {
|
||||
pair_type{ "none", AllClear },
|
||||
pair_type{ "tasks", ValueType::Tasks },
|
||||
pair_type{ "commandHistory", ValueType::CommandHistory },
|
||||
pair_type{ "directoryHistory", ValueType::DirectoryHistory },
|
||||
pair_type{ "quickFix", ValueType::QuickFixes },
|
||||
pair_type{ "all", AllSet },
|
||||
};
|
||||
};
|
||||
|
||||
@ -155,4 +155,15 @@
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
<feature>
|
||||
<name>Feature_QuickFix</name>
|
||||
<description>Enables the Quick Fix menu</description>
|
||||
<id>16599</id>
|
||||
<stage>AlwaysDisabled</stage>
|
||||
<alwaysEnabledBrandingTokens>
|
||||
<brandingToken>Dev</brandingToken>
|
||||
<brandingToken>Canary</brandingToken>
|
||||
</alwaysEnabledBrandingTokens>
|
||||
</feature>
|
||||
|
||||
</featureStaging>
|
||||
|
||||
@ -419,3 +419,7 @@ void ConhostInternalGetSet::InvokeCompletions(std::wstring_view /*menuJson*/, un
|
||||
{
|
||||
// Not implemented for conhost.
|
||||
}
|
||||
void ConhostInternalGetSet::SearchMissingCommand(std::wstring_view /*missingCommand*/)
|
||||
{
|
||||
// Not implemented for conhost.
|
||||
}
|
||||
|
||||
@ -70,6 +70,8 @@ public:
|
||||
|
||||
void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) override;
|
||||
|
||||
void SearchMissingCommand(std::wstring_view missingCommand) override;
|
||||
|
||||
private:
|
||||
Microsoft::Console::IIoProvider& _io;
|
||||
};
|
||||
|
||||
@ -147,6 +147,8 @@ public:
|
||||
|
||||
virtual bool DoVsCodeAction(const std::wstring_view string) = 0;
|
||||
|
||||
virtual bool DoWTAction(const std::wstring_view string) = 0;
|
||||
|
||||
virtual StringHandler DownloadDRCS(const VTInt fontNumber,
|
||||
const VTParameter startChar,
|
||||
const DispatchTypes::DrcsEraseControl eraseControl,
|
||||
|
||||
@ -88,5 +88,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
virtual void NotifyBufferRotation(const int delta) = 0;
|
||||
|
||||
virtual void InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength) = 0;
|
||||
|
||||
virtual void SearchMissingCommand(const std::wstring_view command) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@ -3995,6 +3995,54 @@ bool AdaptDispatch::DoVsCodeAction(const std::wstring_view string)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Performs a Windows Terminal action
|
||||
// - Currently, the actions we support are:
|
||||
// * CmdNotFound: A protocol for passing commands that the shell couldn't resolve
|
||||
// to the terminal. The command is then shared with WinGet to see if it can
|
||||
// find a package that provides that command, which is then displayed to the
|
||||
// user.
|
||||
// - Not actually used in conhost
|
||||
// Arguments:
|
||||
// - string: contains the parameters that define which action we do
|
||||
// Return Value:
|
||||
// - false in conhost, true for the CmdNotFound action, otherwise false.
|
||||
bool AdaptDispatch::DoWTAction(const std::wstring_view string)
|
||||
{
|
||||
// This is not implemented in conhost.
|
||||
if (_api.IsConsolePty())
|
||||
{
|
||||
// Flush the frame manually to make sure this action happens at the right time.
|
||||
_renderer->TriggerFlush(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto parts = Utils::SplitString(string, L';');
|
||||
|
||||
if (parts.size() < 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto action = til::at(parts, 0);
|
||||
|
||||
if (action == L"CmdNotFound")
|
||||
{
|
||||
// The structure of the message is as follows:
|
||||
// `e]9001;
|
||||
// 0: CmdNotFound;
|
||||
// 1: $($cmdNotFound.missingCmd);
|
||||
if (parts.size() >= 2)
|
||||
{
|
||||
const std::wstring_view missingCmd = til::at(parts, 1);
|
||||
_api.SearchMissingCommand(missingCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - DECDLD - Downloads one or more characters of a dynamically redefinable
|
||||
// character set (DRCS) with a specified pixel pattern. The pixel array is
|
||||
|
||||
@ -150,6 +150,8 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
bool DoVsCodeAction(const std::wstring_view string) override;
|
||||
|
||||
bool DoWTAction(const std::wstring_view string) override;
|
||||
|
||||
StringHandler DownloadDRCS(const VTInt fontNumber,
|
||||
const VTParameter startChar,
|
||||
const DispatchTypes::DrcsEraseControl eraseControl,
|
||||
|
||||
@ -140,6 +140,8 @@ public:
|
||||
|
||||
bool DoVsCodeAction(const std::wstring_view /*string*/) override { return false; }
|
||||
|
||||
bool DoWTAction(const std::wstring_view /*string*/) override { return false; }
|
||||
|
||||
StringHandler DownloadDRCS(const VTInt /*fontNumber*/,
|
||||
const VTParameter /*startChar*/,
|
||||
const DispatchTypes::DrcsEraseControl /*eraseControl*/,
|
||||
|
||||
@ -218,6 +218,11 @@ public:
|
||||
VERIFY_ARE_EQUAL(_expectedReplaceLength, replaceLength);
|
||||
}
|
||||
|
||||
void SearchMissingCommand(const std::wstring_view /*command*/) override
|
||||
{
|
||||
Log::Comment(L"SearchMissingCommand MOCK called...");
|
||||
}
|
||||
|
||||
void PrepData()
|
||||
{
|
||||
PrepData(CursorDirection::UP); // if called like this, the cursor direction doesn't matter.
|
||||
|
||||
@ -913,6 +913,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const size_t parameter, const s
|
||||
success = _dispatch->DoVsCodeAction(string);
|
||||
break;
|
||||
}
|
||||
case OscActionCodes::WTAction:
|
||||
{
|
||||
success = _dispatch->DoWTAction(string);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// If no functions to call, overall dispatch was a failure.
|
||||
success = false;
|
||||
|
||||
@ -229,6 +229,7 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
FinalTermAction = 133,
|
||||
VsCodeAction = 633,
|
||||
ITerm2Action = 1337,
|
||||
WTAction = 9001,
|
||||
};
|
||||
|
||||
bool _GetOscSetColorTable(const std::wstring_view string,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user