From bba8aac96d669f0bd06bf18156339c6522b2125e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Sat, 1 Jun 2024 14:37:50 -0500 Subject: [PATCH] use a cache in actionmap to stash commands as we parse them --- .wt.json | 2 +- .../TerminalApp/AppActionHandlers.cpp | 56 ++++++++-------- .../TerminalSettingsModel/ActionMap.cpp | 67 +++++++++++++++++-- .../TerminalSettingsModel/ActionMap.h | 4 +- .../TerminalSettingsModel/ActionMap.idl | 2 +- .../TerminalSettingsModel/Command.cpp | 2 +- 6 files changed, 96 insertions(+), 37 deletions(-) diff --git a/.wt.json b/.wt.json index 83caf18a27a..d3d01f6eff5 100644 --- a/.wt.json +++ b/.wt.json @@ -3,7 +3,7 @@ [ { "command": { "action": "sendInput", "input": "bx\r" }, - "name": "Build project", + "name": "Build projectttttttttttttttttt", "description": "Build the project in the CWD" }, { diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index a323ead5e94..3f225e16612 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -1343,24 +1343,26 @@ namespace winrt::TerminalApp::implementation std::vector commandsCollection; Control::CommandHistoryContext context{ nullptr }; winrt::hstring currentCommandline = L""; + winrt::hstring currentWorkingDirectory = 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::Local); - if (shouldGetContext) - { + // const bool shouldGetContext = realArgs.UseCommandline() || + // WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::Local); + // if (shouldGetContext) + // { if (const auto& control{ _GetActiveControl() }) { context = control.CommandHistory(); if (context) { currentCommandline = context.CurrentCommandline(); + currentWorkingDirectory = context.CurrentWorkingDirectory(); } } - } + // } // Aggregate all the commands from the different sources that // the user selected. @@ -1369,7 +1371,7 @@ namespace winrt::TerminalApp::implementation // their settings file. Ask the ActionMap for those. if (WI_IsFlagSet(source, SuggestionsSource::Tasks)) { - const auto tasks = _settings.GlobalSettings().ActionMap().FilterToSendInput(currentCommandline); + const auto tasks = _settings.GlobalSettings().ActionMap().FilterToSnippets(currentCommandline, currentWorkingDirectory); for (const auto& t : tasks) { commandsCollection.push_back(t); @@ -1389,27 +1391,27 @@ namespace winrt::TerminalApp::implementation } } - if (WI_IsFlagSet(source, SuggestionsSource::Local) && - context != nullptr) - { - // TODO! this is wack. CurrentWorkingDirectory should be it's own - // property, or a property of ControlCore.DirectoryHistory() or - // something. I only have 5 minutes to pch tho so garbage will do - auto cwd = context.CurrentWorkingDirectory();// strongControl.CommandHistory().CurrentWorkingDirectory(); - if (!cwd.empty()) - { - co_await winrt::resume_background(); - auto localTasksFileContents = CascadiaSettings::ReadFile(cwd + L"\\.wt.json"); - if (!localTasksFileContents.empty()) - { - const auto localCommands = Command::ParseLocalCommands(localTasksFileContents); - for (const auto& t : localCommands) - { - commandsCollection.push_back(t); - } - } - } - } + // if (WI_IsFlagSet(source, SuggestionsSource::Local) && + // context != nullptr) + // { + // // TODO! this is wack. CurrentWorkingDirectory should be it's own + // // property, or a property of ControlCore.DirectoryHistory() or + // // something. I only have 5 minutes to pch tho so garbage will do + // auto cwd = context.CurrentWorkingDirectory();// strongControl.CommandHistory().CurrentWorkingDirectory(); + // if (!cwd.empty()) + // { + // co_await winrt::resume_background(); + // auto localTasksFileContents = CascadiaSettings::ReadFile(cwd + L"\\.wt.json"); + // if (!localTasksFileContents.empty()) + // { + // const auto localCommands = Command::ParseLocalCommands(localTasksFileContents); + // for (const auto& t : localCommands) + // { + // commandsCollection.push_back(t); + // } + // } + // } + // } co_await wil::resume_foreground(Dispatcher()); diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.cpp b/src/cascadia/TerminalSettingsModel/ActionMap.cpp index 4f8a1610210..60d3a0f29e7 100644 --- a/src/cascadia/TerminalSettingsModel/ActionMap.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionMap.cpp @@ -824,8 +824,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return _ExpandedCommandsCache; } - IVector _filterToSendInput(IMapView nameMap, - winrt::hstring currentCommandline) + IVector _filterToSnippets(IMapView nameMap, + winrt::hstring currentCommandline, + winrt::hstring currentWorkingDirectory) { auto results = winrt::single_threaded_vector(); @@ -865,7 +866,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation else if (command.HasNestedCommands()) { // Look for any sendInput commands nested underneath us - auto innerResults = _filterToSendInput(command.NestedCommands(), currentCommandline); + auto innerResults = _filterToSnippets(command.NestedCommands(), currentCommandline, currentWorkingDirectory); if (innerResults.Size() > 0) { @@ -886,9 +887,63 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return results; } - IVector ActionMap::FilterToSendInput( - winrt::hstring currentCommandline) + IVector ActionMap::FilterToSnippets( + winrt::hstring currentCommandline, + winrt::hstring currentWorkingDirectory) { - return _filterToSendInput(NameMap(), currentCommandline); + auto results = _filterToSnippets(NameMap(), currentCommandline, currentWorkingDirectory); + + auto cachedCwdCommands = _cwdLocalSnippetsCache.find(currentWorkingDirectory); + if (cachedCwdCommands == _cwdLocalSnippetsCache.end()) + { + // we haven't cached this path yet + + auto localTasksFileContents = CascadiaSettings::ReadFile(currentWorkingDirectory + L"\\.wt.json"); + if (!localTasksFileContents.empty()) + { + // const auto localCommands = Command::ParseLocalCommands(localTasksFileContents); + // for (const auto& t : localCommands) + // { + // commandsCollection.push_back(t); + // } + + auto data = winrt::to_string(localTasksFileContents); + std::string errs; + static std::unique_ptr reader{ Json::CharReaderBuilder::CharReaderBuilder().newCharReader() }; + Json::Value root; + if (!reader->parse(data.data(), data.data() + data.size(), &root, &errs)) + { + throw winrt::hresult_error(WEB_E_INVALID_JSON_STRING, winrt::to_hstring(errs)); + } + + auto result = std::vector(); + if (auto actions{ root[JsonKey("actions")] }) + { + std::vector warnings; + for (const auto& json : actions) + { + auto parsed = Command::FromJson(json, warnings, OriginTag::Generated); + if (parsed->ActionAndArgs().Action() != ShortcutAction::SendInput) + continue; + // commands.Append(*parsed); + result.push_back(*parsed); + } + } + + _cwdLocalSnippetsCache.insert_or_assign(currentWorkingDirectory, result); + cachedCwdCommands = _cwdLocalSnippetsCache.find(currentWorkingDirectory); + } + } + + if (cachedCwdCommands != _cwdLocalSnippetsCache.end()) + { + const auto commands = cachedCwdCommands->second; + for (const auto& cmd : commands) + { + results.Append(cmd); + } + } + + return results; } } diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.h b/src/cascadia/TerminalSettingsModel/ActionMap.h index d2d078da83e..3f882703134 100644 --- a/src/cascadia/TerminalSettingsModel/ActionMap.h +++ b/src/cascadia/TerminalSettingsModel/ActionMap.h @@ -83,7 +83,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation void ExpandCommands(const Windows::Foundation::Collections::IVectorView& profiles, const Windows::Foundation::Collections::IMapView& schemes); - winrt::Windows::Foundation::Collections::IVector FilterToSendInput(winrt::hstring currentCommandline); + winrt::Windows::Foundation::Collections::IVector FilterToSnippets(winrt::hstring currentCommandline, winrt::hstring currentWorkingDirectory); private: Model::Command _GetActionByID(const winrt::hstring actionID) const; @@ -128,6 +128,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation // we can give the SUI a view of the key chords and the commands they map to Windows::Foundation::Collections::IMap _ResolvedKeyActionMapCache{ nullptr }; + std::unordered_map> _cwdLocalSnippetsCache{}; + friend class SettingsModelUnitTests::KeyBindingsTests; friend class SettingsModelUnitTests::DeserializationTests; friend class SettingsModelUnitTests::TerminalSettingsTests; diff --git a/src/cascadia/TerminalSettingsModel/ActionMap.idl b/src/cascadia/TerminalSettingsModel/ActionMap.idl index 6b3eb30e628..b9e520b1e3a 100644 --- a/src/cascadia/TerminalSettingsModel/ActionMap.idl +++ b/src/cascadia/TerminalSettingsModel/ActionMap.idl @@ -22,7 +22,7 @@ namespace Microsoft.Terminal.Settings.Model IVector ExpandedCommands { get; }; - IVector FilterToSendInput(String CurrentCommandline); + IVector FilterToSnippets(String CurrentCommandline, String CurrentWorkingDirectory); }; [default_interface] runtimeclass ActionMap : IActionMapView diff --git a/src/cascadia/TerminalSettingsModel/Command.cpp b/src/cascadia/TerminalSettingsModel/Command.cpp index c67320c8de0..c074143d07b 100644 --- a/src/cascadia/TerminalSettingsModel/Command.cpp +++ b/src/cascadia/TerminalSettingsModel/Command.cpp @@ -724,7 +724,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation std::vector warnings; for (const auto& json : actions) { - auto parsed = Command::FromJson(json, warnings, OriginTag::Generated, false); + auto parsed = Command::FromJson(json, warnings, OriginTag::Generated); if (parsed->ActionAndArgs().Action() != ShortcutAction::SendInput) continue; // commands.Append(*parsed);