@@ -916,14 +916,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
916
916
AddAction (*cmd, keys);
917
917
}
918
918
919
- // Update ActionMap's cache of actions for this directory. We'll look for a
920
- // .wt.json in this directory. If it exists, we'll read it, parse it's JSON,
921
- // then take all the sendInput actions in it and store them in our
922
- // _cwdLocalSnippetsCache
923
- std::vector<Model::Command> ActionMap::_updateLocalSnippetCache (winrt::hstring currentWorkingDirectory)
919
+ // Look for a .wt.json file in the given directory. If it exists,
920
+ // read it, parse it's JSON, and retrieve all the sendInput actions.
921
+ std::unordered_map<hstring, Model::Command> ActionMap::_loadLocalSnippets (const std::filesystem::path& currentWorkingDirectory)
924
922
{
925
923
// This returns an empty string if we fail to load the file.
926
- std::filesystem::path localSnippetsPath{ std::wstring_view{ currentWorkingDirectory + L" \\ .wt.json" } };
924
+ std::filesystem::path localSnippetsPath = currentWorkingDirectory / std::filesystem::path{ " .wt.json" };
927
925
const auto data = til::io::read_file_as_utf8_string_if_exists (localSnippetsPath);
928
926
if (data.empty ())
929
927
{
@@ -943,12 +941,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
943
941
return {};
944
942
}
945
943
946
- auto result = std::vector< Model::Command>() ;
944
+ std::unordered_map<hstring, Model::Command> result ;
947
945
if (auto actions{ root[JsonKey (" snippets" )] })
948
946
{
949
947
for (const auto & json : actions)
950
948
{
951
- result.push_back (*Command::FromSnippetJson (json));
949
+ const auto snippet = Command::FromSnippetJson (json);
950
+ result.insert_or_assign (snippet->Name (), *snippet);
952
951
}
953
952
}
954
953
return result;
@@ -958,34 +957,89 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
958
957
winrt::hstring currentCommandline,
959
958
winrt::hstring currentWorkingDirectory)
960
959
{
960
+ // enumerate all the parent directories we want to import snippets from
961
+ std::filesystem::path directory{ std::wstring_view{ currentWorkingDirectory } };
962
+ std::vector<std::filesystem::path> directories;
963
+ while (!directory.empty ())
961
964
{
962
- // Check if there are any cached commands in this directory.
963
- const auto & cache{ _cwdLocalSnippetsCache.lock_shared () };
965
+ directories.push_back (directory);
966
+ auto parentPath = directory.parent_path ();
967
+ if (directory == parentPath)
968
+ {
969
+ break ;
970
+ }
971
+ directory = std::move (parentPath);
972
+ }
964
973
965
- const auto cacheIterator = cache->find (currentWorkingDirectory);
966
- if (cacheIterator != cache->end ())
974
+ {
975
+ // Check if all the directories are already in the cache
976
+ const auto & cache{ _cwdLocalSnippetsCache.lock_shared () };
977
+ if (std::ranges::all_of (directories, [&](auto && dir) { return cache->contains (dir); }))
967
978
{
968
- // We found something in the cache! return it.
979
+ // Load snippets from directories in reverse order.
980
+ // This ensures that we prioritize snippets closer to the cwd.
981
+ // The map makes it easy to avoid duplicates.
982
+ std::unordered_map<hstring, Model::Command> localSnippetsMap;
983
+ for (auto rit = directories.rbegin (); rit != directories.rend (); ++rit)
984
+ {
985
+ // register snippets from cache
986
+ for (const auto & [name, snippet] : cache->at (*rit))
987
+ {
988
+ localSnippetsMap.insert_or_assign (name, snippet);
989
+ }
990
+ }
991
+
992
+ std::vector<Model::Command> localSnippets;
993
+ localSnippets.reserve (localSnippetsMap.size ());
994
+ std::ranges::transform (localSnippetsMap,
995
+ std::back_inserter (localSnippets),
996
+ [](const auto & kvPair) { return kvPair.second ; });
969
997
co_return winrt::single_threaded_vector<Model::Command>(_filterToSnippets (NameMap (),
970
998
currentCommandline,
971
- cacheIterator-> second ));
999
+ localSnippets ));
972
1000
}
973
1001
} // release the lock on the cache
974
1002
975
1003
// Don't do I/O on the main thread
976
1004
co_await winrt::resume_background ();
977
1005
978
- auto result = _updateLocalSnippetCache (currentWorkingDirectory);
979
- if (!result.empty ())
1006
+ // Load snippets from directories in reverse order.
1007
+ // This ensures that we prioritize snippets closer to the cwd.
1008
+ // The map makes it easy to avoid duplicates.
1009
+ const auto & cache{ _cwdLocalSnippetsCache.lock () };
1010
+ std::unordered_map<hstring, Model::Command> localSnippetsMap;
1011
+ for (auto rit = directories.rbegin (); rit != directories.rend (); ++rit)
980
1012
{
981
- // We found something! Add it to the cache
982
- auto cache{ _cwdLocalSnippetsCache.lock () };
983
- cache->insert_or_assign (currentWorkingDirectory, result);
1013
+ const auto & dir = *rit;
1014
+ if (const auto cacheIterator = cache->find (dir); cacheIterator != cache->end ())
1015
+ {
1016
+ // register snippets from cache
1017
+ for (const auto & [name, snippet] : cache->at (*rit))
1018
+ {
1019
+ localSnippetsMap.insert_or_assign (name, snippet);
1020
+ }
1021
+ }
1022
+ else
1023
+ {
1024
+ // we don't have this directory in the cache, so we need to load it
1025
+ auto result = _loadLocalSnippets (dir);
1026
+ cache->insert_or_assign (dir, result);
1027
+
1028
+ // register snippets from cache
1029
+ std::ranges::for_each (result, [&localSnippetsMap](const auto & kvPair) {
1030
+ localSnippetsMap.insert_or_assign (kvPair.first , kvPair.second );
1031
+ });
1032
+ }
984
1033
}
985
1034
1035
+ std::vector<Model::Command> localSnippets;
1036
+ localSnippets.reserve (localSnippetsMap.size ());
1037
+ std::ranges::transform (localSnippetsMap,
1038
+ std::back_inserter (localSnippets),
1039
+ [](const auto & kvPair) { return kvPair.second ; });
986
1040
co_return winrt::single_threaded_vector<Model::Command>(_filterToSnippets (NameMap (),
987
1041
currentCommandline,
988
- result ));
1042
+ localSnippets ));
989
1043
}
990
1044
#pragma endregion
991
1045
}
0 commit comments