Skip to content

Commit

Permalink
Add a useCommandline property to the suggestions action (#15027)
Browse files Browse the repository at this point in the history
_targets #14943_

When this is true, this will re-use the existing commandline to
pre-filter the results. This is especially helpful for completing a
suggestion based on the text that's already been typed.

Like with command history, this requires that shell integration is
enabled before it will work.## Summary of the Pull Request

## References and Relevant Issues

See also #13445 
As spec'd in #14864 

## Validation Steps Performed

Tested manually
  • Loading branch information
zadjii-msft committed Aug 15, 2023
1 parent 8f4c63e commit 3afe7a8
Show file tree
Hide file tree
Showing 16 changed files with 101 additions and 41 deletions.
16 changes: 16 additions & 0 deletions src/buffer/out/textBuffer.cpp
Expand Up @@ -2985,6 +2985,22 @@ void TextBuffer::_trimMarksOutsideBuffer()
_marks.end());
}

std::wstring_view TextBuffer::CurrentCommand() const
{
if (_marks.size() == 0)
{
return L"";
}

const auto& curr{ _marks.back() };
const auto& start{ curr.end };
const auto& end{ GetCursor().GetPosition() };

const auto line = start.y;
const auto& row = GetRowByOffset(line);
return row.GetText(start.x, end.x);
}

void TextBuffer::SetCurrentPromptEnd(const til::point pos) noexcept
{
if (_marks.empty())
Expand Down
1 change: 1 addition & 0 deletions src/buffer/out/textBuffer.hpp
Expand Up @@ -276,6 +276,7 @@ class TextBuffer final
void SetCurrentPromptEnd(const til::point pos) noexcept;
void SetCurrentCommandEnd(const til::point pos) noexcept;
void SetCurrentOutputEnd(const til::point pos, ::MarkCategory category) noexcept;
std::wstring_view CurrentCommand() const;

private:
void _reserve(til::size screenBufferSize, const TextAttribute& defaultAttributes);
Expand Down
6 changes: 4 additions & 2 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Expand Up @@ -1273,9 +1273,11 @@ namespace winrt::TerminalApp::implementation
if (const auto& control{ _GetActiveControl() })
{
const auto context = control.CommandHistory();
const auto& currentCmd{ realArgs.UseCommandline() ? context.CurrentCommandline() : L"" };
_OpenSuggestions(control,
Command::HistoryToCommands(context.History(), context.CurrentCommandline(), false),
SuggestionsMode::Palette);
Command::HistoryToCommands(context.History(), currentCmd, false),
SuggestionsMode::Palette,
currentCmd);
}
args.Handled(true);
}
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/SuggestionsControl.cpp
Expand Up @@ -1051,6 +1051,7 @@ namespace winrt::TerminalApp::implementation

void SuggestionsControl::Open(TerminalApp::SuggestionsMode mode,
const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command>& commands,
winrt::hstring filter,
Windows::Foundation::Point anchor,
Windows::Foundation::Size space,
float characterHeight)
Expand Down Expand Up @@ -1101,5 +1102,8 @@ namespace winrt::TerminalApp::implementation
newMargin.Top = (_anchor.Y - actualSize.height);
}
Margin(newMargin);

_searchBox().Text(filter);
}

}
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/SuggestionsControl.h
Expand Up @@ -42,6 +42,7 @@ namespace winrt::TerminalApp::implementation

void Open(TerminalApp::SuggestionsMode mode,
const Windows::Foundation::Collections::IVector<Microsoft::Terminal::Settings::Model::Command>& commands,
winrt::hstring filterText,
Windows::Foundation::Point anchor,
Windows::Foundation::Size space,
float characterHeight);
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/SuggestionsControl.idl
Expand Up @@ -40,7 +40,7 @@ namespace TerminalApp
void SetActionMap(Microsoft.Terminal.Settings.Model.IActionMapView actionMap);
void SelectNextItem(Boolean moveDown);

void Open(SuggestionsMode mode, IVector<Microsoft.Terminal.Settings.Model.Command> commands, Windows.Foundation.Point anchor, Windows.Foundation.Size space, Single characterHeight);
void Open(SuggestionsMode mode, IVector<Microsoft.Terminal.Settings.Model.Command> commands, String filterText, Windows.Foundation.Point anchor, Windows.Foundation.Size space, Single characterHeight);

event Windows.Foundation.TypedEventHandler<SuggestionsControl, Microsoft.Terminal.Settings.Model.Command> DispatchCommandRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Settings.Model.Command> PreviewAction;
Expand Down
13 changes: 10 additions & 3 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Expand Up @@ -4718,7 +4718,7 @@ namespace winrt::TerminalApp::implementation
if (const auto& page{ weakThis.get() })
{
// Open the Suggestions UI with the commands from the control
page->_OpenSuggestions(sender.try_as<TermControl>(), commandsCollection, SuggestionsMode::Menu);
page->_OpenSuggestions(sender.try_as<TermControl>(), commandsCollection, SuggestionsMode::Menu, L"");
}
});
}
Expand All @@ -4728,7 +4728,9 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_OpenSuggestions(
const TermControl& sender,
IVector<Command> commandsCollection,
winrt::TerminalApp::SuggestionsMode mode)
winrt::TerminalApp::SuggestionsMode mode,
winrt::hstring filterText)

{
// ON THE UI THREAD
assert(Dispatcher().HasThreadAccess());
Expand Down Expand Up @@ -4761,7 +4763,12 @@ namespace winrt::TerminalApp::implementation
const auto realCursorPos{ controlTransform.TransformPoint({ cursorPos.X, cursorPos.Y }) }; // == controlTransform + cursorPos
const Windows::Foundation::Size windowDimensions{ gsl::narrow_cast<float>(ActualWidth()), gsl::narrow_cast<float>(ActualHeight()) };

sxnUi.Open(mode, commandsCollection, realCursorPos, windowDimensions, characterSize.Height);
sxnUi.Open(mode,
commandsCollection,
filterText,
realCursorPos,
windowDimensions,
characterSize.Height);
}

void TerminalPage::_ContextMenuOpened(const IInspectable& sender,
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalApp/TerminalPage.h
Expand Up @@ -519,7 +519,8 @@ namespace winrt::TerminalApp::implementation
void _updatePaneResources(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);

winrt::fire_and_forget _ControlCompletionsChangedHandler(const winrt::Windows::Foundation::IInspectable sender, const winrt::Microsoft::Terminal::Control::CompletionsChangedEventArgs args);
void _OpenSuggestions(const Microsoft::Terminal::Control::TermControl& sender, Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Model::Command> commandsCollection, winrt::TerminalApp::SuggestionsMode mode);

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);

Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Expand Up @@ -1958,6 +1958,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto& textBuffer = _terminal->GetTextBuffer();

std::vector<winrt::hstring> commands;

for (const auto& mark : _terminal->GetScrollMarks())
{
// The command text is between the `end` (which denotes the end of
Expand All @@ -1979,10 +1980,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (strEnd != std::string::npos)
{
const auto trimmed = commandText.substr(0, strEnd + 1);

commands.push_back(winrt::hstring{ trimmed });
}
}
auto context = winrt::make_self<CommandHistoryContext>(std::move(commands));
context->CurrentCommandline(winrt::hstring{ _terminal->CurrentCommand() });

return *context;
}
Expand Down
10 changes: 10 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Expand Up @@ -1451,6 +1451,16 @@ til::color Terminal::GetColorForMark(const ScrollMark& mark) const
}
}

std::wstring_view Terminal::CurrentCommand() const
{
if (_currentPromptState != PromptState::Command)
{
return L"";
}

return _activeBuffer().CurrentCommand();
}

void Terminal::ColorSelection(const TextAttribute& attr, winrt::Microsoft::Terminal::Core::MatchMode matchMode)
{
for (const auto [start, end] : _GetSelectionSpans())
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Expand Up @@ -119,6 +119,8 @@ class Microsoft::Terminal::Core::Terminal final :
const til::point& end,
const bool fromUi);

std::wstring_view CurrentCommand() const;

#pragma region ITerminalApi
// These methods are defined in TerminalApi.cpp
void ReturnResponse(const std::wstring_view response) override;
Expand Down
15 changes: 13 additions & 2 deletions src/cascadia/TerminalSettingsModel/ActionArgs.cpp
Expand Up @@ -709,12 +709,23 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation

winrt::hstring SuggestionsArgs::GenerateName() const
{
auto base{ RS_(L"SuggestionsCommandKey") };
switch (Source())
{
case SuggestionsSource::CommandHistory:
return RS_(L"SuggestionsCommandHistoryCommandKey");
base = RS_(L"SuggestionsCommandHistoryCommandKey");
}

if (UseCommandline())
{
return winrt::hstring{
fmt::format(L"{}, useCommandline:true", std::wstring_view(base))
};
}
else
{
return base;
}
return RS_(L"SuggestionsCommandKey");
}

winrt::hstring FindMatchArgs::GenerateName() const
Expand Down
5 changes: 3 additions & 2 deletions src/cascadia/TerminalSettingsModel/ActionArgs.h
Expand Up @@ -215,8 +215,9 @@ private: \
X(CommandPaletteLaunchMode, LaunchMode, "launchMode", false, CommandPaletteLaunchMode::Action)

////////////////////////////////////////////////////////////////////////////////
#define SUGGESTIONS_ARGS(X) \
X(SuggestionsSource, Source, "source", false, SuggestionsSource::Tasks)
#define SUGGESTIONS_ARGS(X) \
X(SuggestionsSource, Source, "source", false, SuggestionsSource::Tasks) \
X(bool, UseCommandline, "useCommandline", false, false)

////////////////////////////////////////////////////////////////////////////////
#define FIND_MATCH_ARGS(X) \
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalSettingsModel/ActionArgs.idl
Expand Up @@ -327,8 +327,9 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass SuggestionsArgs : IActionArgs
{
SuggestionsArgs();
SuggestionsArgs(SuggestionsSource source);
SuggestionsArgs(SuggestionsSource source, Boolean useCommandline);
SuggestionsSource Source { get; };
Boolean UseCommandline { get; };
};

[default_interface] runtimeclass FindMatchArgs : IActionArgs
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/TerminalSettingsModel/Command.cpp
Expand Up @@ -738,7 +738,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// * If directories is true, we'll prepend "cd " to each command, so that
// the command will be run as a directory change instead.
IVector<Model::Command> Command::HistoryToCommands(IVector<winrt::hstring> history,
winrt::hstring /*currentCommandline*/,
winrt::hstring currentCommandline,
bool directories)
{
std::wstring cdText = directories ? L"cd " : L"";
Expand All @@ -747,7 +747,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// Use this map to discard duplicates.
std::unordered_map<std::wstring_view, bool> foundCommands{};

auto backspaces = std::wstring(::base::saturated_cast<size_t>(0), L'\x7f');
auto backspaces = std::wstring(currentCommandline.size(), L'\x7f');

// Iterate in reverse over the history, so that most recent commands are first
for (auto i = history.Size(); i > 0; i--)
Expand Down
54 changes: 27 additions & 27 deletions src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--

This comment has been minimized.

Copy link
@DHowett

DHowett Aug 15, 2023

Member

@zadjii-msft I s2g you actually committed a resw file with bad spacing

Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
Expand All @@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
Expand Down

0 comments on commit 3afe7a8

Please sign in to comment.