Skip to content

Commit

Permalink
Add support for local snippets in the CWD (#17388)
Browse files Browse the repository at this point in the history
This PR adds the ability to load snippets from the CWD into the
suggestions UI.

If shell integration is disabled, then we only ever think the CWD for a
pane is it's `startingDirectory`. So, in the default case, users can
still stick snippets into the root of their git repos, and have the
Terminal load them automatically (for profiles starting in the root of
their repo).
If it's enabled though, we'll always try to load snippets from the CWD
of the shell.

* We cache the actions into a separate map of CWD -> actions. This lets
us read the file only the first time we see a dir.
* We clear that cache on settings reload
* We only load `sendInput` actions from the `.wt.json`

As spec'd in #17329
  • Loading branch information
zadjii-msft authored Jul 26, 2024
1 parent 7851c96 commit 21fa303
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 80 deletions.
28 changes: 28 additions & 0 deletions .wt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"$version": "1.0.0",
"snippets":
[
{
"input": "bx\r",
"name": "Build project",
"description": "Build the project in the CWD"
},
{
"input": "bz\r",
"name": "Build solution, incremental",
"description": "Just build changes to the solution"
},
{
"input": "bcz\r",
"name": "Clean & build solution",
"icon": "\uE8e6",
"description": "Start over. Go get your coffee. "
},
{
"input": "nuget push -ApiKey az -source TerminalDependencies %userprofile%\\Downloads",
"name": "Upload package to nuget feed",
"icon": "\uE898",
"description": "Go download a .nupkg, put it in ~/Downloads, and use this to push to our private feed."
}
]
}
134 changes: 72 additions & 62 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1437,77 +1437,87 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<SuggestionsArgs>())
{
const auto source = realArgs.Source();
std::vector<Command> commandsCollection;
Control::CommandHistoryContext context{ nullptr };
winrt::hstring currentCommandline = L"";

// If the user wanted to use the current commandline to filter results,
// OR they wanted command history (or some other source that
// requires context from the control)
// then get that here.
const bool shouldGetContext = realArgs.UseCommandline() ||
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
if (shouldGetContext)
{
if (const auto& control{ _GetActiveControl() })
{
context = control.CommandHistory();
if (context)
{
currentCommandline = context.CurrentCommandline();
}
}
}
_doHandleSuggestions(realArgs);
args.Handled(true);
}
}
}

// Aggregate all the commands from the different sources that
// the user selected. This is the order presented to the user
winrt::fire_and_forget TerminalPage::_doHandleSuggestions(SuggestionsArgs realArgs)
{
const auto source = realArgs.Source();
std::vector<Command> commandsCollection;
Control::CommandHistoryContext context{ nullptr };
winrt::hstring currentCommandline = L"";
winrt::hstring currentWorkingDirectory = L"";

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);
}
}
// If the user wanted to use the current commandline to filter results,
// OR they wanted command history (or some other source that
// requires context from the control)
// then get that here.
const bool shouldGetContext = realArgs.UseCommandline() ||
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
if (const auto& control{ _GetActiveControl() })
{
currentWorkingDirectory = control.CurrentWorkingDirectory();

// Tasks are all the sendInput commands the user has saved in
// their settings file. Ask the ActionMap for those.
if (WI_IsFlagSet(source, SuggestionsSource::Tasks))
if (shouldGetContext)
{
context = control.CommandHistory();
if (context)
{
const auto tasks = _settings.GlobalSettings().ActionMap().FilterToSendInput(currentCommandline);
for (const auto& t : tasks)
{
commandsCollection.push_back(t);
}
currentCommandline = context.CurrentCommandline();
}
}
}

// Command History comes from the commands in the buffer,
// assuming the user has enabled shell integration. Get those
// from the active control.
if (WI_IsFlagSet(source, SuggestionsSource::CommandHistory) &&
context != nullptr)
{
// \ue81c --> History icon
const auto recentCommands = Command::HistoryToCommands(context.History(), currentCommandline, false, hstring{ L"\ue81c" });
for (const auto& t : recentCommands)
{
commandsCollection.push_back(t);
}
}
// Aggregate all the commands from the different sources that
// the user selected.

// Open the palette with all these commands in it.
_OpenSuggestions(_GetActiveControl(),
winrt::single_threaded_vector<Command>(std::move(commandsCollection)),
SuggestionsMode::Palette,
currentCommandline);
args.Handled(true);
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);
}
}

// Tasks are all the sendInput commands the user has saved in
// their settings file. Ask the ActionMap for those.
if (WI_IsFlagSet(source, SuggestionsSource::Tasks))
{
const auto tasks = co_await _settings.GlobalSettings().ActionMap().FilterToSnippets(currentCommandline, currentWorkingDirectory);
// ----- we may be on a background thread here -----
for (const auto& t : tasks)
{
commandsCollection.push_back(t);
}
}

// Command History comes from the commands in the buffer,
// assuming the user has enabled shell integration. Get those
// from the active control.
if (WI_IsFlagSet(source, SuggestionsSource::CommandHistory) &&
context != nullptr)
{
const auto recentCommands = Command::HistoryToCommands(context.History(), currentCommandline, false, hstring{ L"\ue81c" });
for (const auto& t : recentCommands)
{
commandsCollection.push_back(t);
}
}

co_await wil::resume_foreground(Dispatcher());

// Open the palette with all these commands in it.
_OpenSuggestions(_GetActiveControl(),
winrt::single_threaded_vector<Command>(std::move(commandsCollection)),
SuggestionsMode::Palette,
currentCommandline);
}

void TerminalPage::_HandleColorSelection(const IInspectable& /*sender*/,
Expand Down
6 changes: 4 additions & 2 deletions src/cascadia/TerminalApp/SnippetsPaneContent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace winrt::TerminalApp::implementation
}
}

void SnippetsPaneContent::UpdateSettings(const CascadiaSettings& settings)
winrt::fire_and_forget SnippetsPaneContent::UpdateSettings(const CascadiaSettings& settings)
{
_settings = settings;

Expand All @@ -51,7 +51,9 @@ namespace winrt::TerminalApp::implementation
// has typed, then relies on the suggestions UI to _also_ filter with that
// string.

const auto tasks = _settings.GlobalSettings().ActionMap().FilterToSendInput(winrt::hstring{}); // IVector<Model::Command>
const auto tasks = co_await _settings.GlobalSettings().ActionMap().FilterToSnippets(winrt::hstring{}, winrt::hstring{}); // IVector<Model::Command>
co_await wil::resume_foreground(Dispatcher());

_allTasks = winrt::single_threaded_observable_vector<TerminalApp::FilteredTask>();
for (const auto& t : tasks)
{
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalApp/SnippetsPaneContent.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace winrt::TerminalApp::implementation

winrt::Windows::UI::Xaml::FrameworkElement GetRoot();

void UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
winrt::fire_and_forget UpdateSettings(const winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);

winrt::Windows::Foundation::Size MinimumSize();
void Focus(winrt::Windows::UI::Xaml::FocusState reason = winrt::Windows::UI::Xaml::FocusState::Programmatic);
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ namespace winrt::TerminalApp::implementation
winrt::com_ptr<TerminalTab> _senderOrFocusedTab(const IInspectable& sender);

void _activePaneChanged(winrt::TerminalApp::TerminalTab tab, Windows::Foundation::IInspectable args);
winrt::fire_and_forget _doHandleSuggestions(Microsoft::Terminal::Settings::Model::SuggestionsArgs realArgs);

#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2318,6 +2318,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return *context;
}

winrt::hstring ControlCore::CurrentWorkingDirectory() const
{
return winrt::hstring{ _terminal->GetWorkingDirectory() };
}

bool ControlCore::QuickFixesAvailable() const noexcept
{
return _cachedQuickFixes && _cachedQuickFixes.Size() > 0;
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation

void ContextMenuSelectCommand();
void ContextMenuSelectOutput();

winrt::hstring CurrentWorkingDirectory() const;
#pragma endregion

#pragma region ITerminalInput
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/ICoreState.idl
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,7 @@ namespace Microsoft.Terminal.Control
void SelectOutput(Boolean goUp);
IVector<ScrollMark> ScrollMarks { get; };

String CurrentWorkingDirectory { get; };

};
}
4 changes: 4 additions & 0 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3639,6 +3639,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return _core.CommandHistory();
}
winrt::hstring TermControl::CurrentWorkingDirectory() const
{
return _core.CurrentWorkingDirectory();
}

void TermControl::UpdateWinGetSuggestions(Windows::Foundation::Collections::IVector<hstring> suggestions)
{
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void SelectCommand(const bool goUp);
void SelectOutput(const bool goUp);

winrt::hstring CurrentWorkingDirectory() const;
#pragma endregion

void ScrollViewport(int viewTop);
Expand Down
Loading

0 comments on commit 21fa303

Please sign in to comment.