Skip to content

Commit e56eb74

Browse files
committed
improve indexing perf and include help text
1 parent cac844b commit e56eb74

File tree

4 files changed

+366
-179
lines changed

4 files changed

+366
-179
lines changed

src/cascadia/TerminalSettingsEditor/MainPage.cpp

Lines changed: 202 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#include <..\WinRTUtils\inc\Utils.h>
2525
#include "GeneratedSettingsIndex.g.h"
2626

27+
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
2728
#include <LibraryResources.h>
29+
#include <ScopedResourceLoader.h>
2830
#include <dwmapi.h>
2931
#include <fmt/compile.h>
3032

@@ -55,6 +57,15 @@ static const std::wstring_view addProfileTag{ L"AddProfile" };
5557
static const std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" };
5658
static const std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" };
5759

60+
// Like RS_, but uses an ambient context to determine whether
61+
// to load the English verion of a resource or the localized one.
62+
#define RS_switchable_(x) RS_switchable_impl(context, USES_RESOURCE(x))
63+
64+
static winrt::hstring RS_switchable_impl(const winrt::Windows::ApplicationModel::Resources::Core::ResourceContext& context, std::wstring_view key)
65+
{
66+
return GetLibraryResourceLoader().ResourceMap().GetValue(key, context).ValueAsString();
67+
}
68+
5869
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
5970
{
6071
static Editor::ProfileViewModel _viewModelForProfile(const Model::Profile& profile, const Model::CascadiaSettings& appSettings, const Windows::UI::Core::CoreDispatcher& dispatcher)
@@ -155,6 +166,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
155166

156167
_breadcrumbs = single_threaded_observable_vector<IInspectable>();
157168
_UpdateSearchIndex();
169+
extensionsVMImpl->LazyLoadExtensions();
158170
}
159171

160172
// Method Description:
@@ -1080,11 +1092,92 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
10801092
}
10811093
else
10821094
{
1095+
// Package filtered search index objects into WinRT FilteredSearchResults for UI
10831096
for (const auto* indexEntry : *_filteredSearchIndex)
10841097
{
1085-
results.push_back(winrt::make<FilteredSearchResult>(*indexEntry));
1098+
results.push_back(winrt::make<FilteredSearchResult>(indexEntry));
1099+
}
1100+
1101+
// TODO CARLOS: use the macro below for runtime objects once everything is verified to be working right
1102+
#define APPEND_RUNTIME_OBJECT_RESULTS(runtimeObjectList, runtimeObjectIdentifier, filteredSearchIndex, navigationArgOverride) \
1103+
for (const auto& runtimeObj : runtimeObjectList) \
1104+
{ \
1105+
if (til::contains_linguistic_insensitive(runtimeObjectIdentifier, sanitizedQuery)) \
1106+
{ \
1107+
/*results.push_back(winrt::make<FilteredSearchResult>(, profile));*/ \
1108+
} \
1109+
\
1110+
for (const auto* indexEntry : filteredSearchIndex) \
1111+
{ \
1112+
results.push_back(winrt::make<FilteredSearchResult>(indexEntry, navigationArgOverride)); \
1113+
} \
1114+
}
1115+
1116+
// Profiles
1117+
//APPEND_RUNTIME_OBJECT_RESULTS(_profileVMs, runtimeObj.Name(), _filteredSearchProfileIndex, runtimeObj)
1118+
for (const auto& profile : _profileVMs)
1119+
{
1120+
// TODO CARLOS: replace with fuzzy search
1121+
if (til::contains_linguistic_insensitive(profile.Name(), sanitizedQuery))
1122+
{
1123+
// TODO CARLOS: if name matches, link the top-level page
1124+
// can't do that rn because I need a LocalizedIndexEntry stored somewhere for that
1125+
//results.push_back(winrt::make<FilteredSearchResult>(, profile));
1126+
}
1127+
1128+
for (const auto* indexEntry : _filteredSearchProfileIndex)
1129+
{
1130+
results.push_back(winrt::make<FilteredSearchResult>(indexEntry, profile));
1131+
}
1132+
}
1133+
1134+
// New Tab Menu (Folder View)
1135+
//APPEND_RUNTIME_OBJECT_RESULTS(get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList(), runtimeObj.Name(), _filteredSearchNTMFolderIndex, runtimeObj)
1136+
for (const auto& ntmFolder : get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList())
1137+
{
1138+
if (til::contains_linguistic_insensitive(ntmFolder.Name(), sanitizedQuery))
1139+
{
1140+
// TODO CARLOS: if name matches, link the top-level page
1141+
// can't do that rn because I need a LocalizedIndexEntry stored somewhere for that
1142+
//results.push_back(winrt::make<FilteredSearchResult>(, ntmFolder));
1143+
}
1144+
1145+
for (const auto* indexEntry : _filteredSearchNTMFolderIndex)
1146+
{
1147+
results.push_back(winrt::make<FilteredSearchResult>(indexEntry, ntmFolder));
1148+
}
1149+
}
1150+
1151+
// Color schemes
1152+
//APPEND_RUNTIME_OBJECT_RESULTS(_colorSchemesPageVM.AllColorSchemes(), runtimeObj.Name(), _filteredSearchColorSchemeIndex, winrt::box_value(runtimeObj.Name()))
1153+
for (const auto& scheme : _colorSchemesPageVM.AllColorSchemes())
1154+
{
1155+
if (til::contains_linguistic_insensitive(scheme.Name(), sanitizedQuery))
1156+
{
1157+
// TODO CARLOS: if name matches, link the top-level page
1158+
// can't do that rn because I need a LocalizedIndexEntry stored somewhere for that
1159+
//results.push_back(winrt::make<FilteredSearchResult>(, scheme));
1160+
}
1161+
1162+
for (const auto* indexEntry : _filteredSearchColorSchemeIndex)
1163+
{
1164+
results.push_back(winrt::make<FilteredSearchResult>(indexEntry, winrt::box_value(scheme.Name())));
1165+
}
1166+
}
1167+
1168+
// TODO CARLOS:
1169+
// - if match with extension name, go to extension page
1170+
for (const auto& extension : _extensionsVM.ExtensionPackages())
1171+
{
1172+
if (til::contains_linguistic_insensitive(extension.Package().DisplayName(), sanitizedQuery))
1173+
{
1174+
// TODO CARLOS: if name matches, link the top-level page
1175+
// can't do that rn because I need a LocalizedIndexEntry stored somewhere for that
1176+
//results.push_back(winrt::make<FilteredSearchResult>(, ntmFolder));
1177+
}
10861178
}
10871179
}
1180+
#undef APPEND_RUNTIME_OBJECT_RESULTS
10881181

10891182
// Update the UI with the results
10901183
const auto& searchBox = SettingsSearchBox();
@@ -1097,16 +1190,35 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
10971190
{
10981191
auto filteredResults{ _filteredSearchIndex.write() };
10991192

1100-
filteredResults->clear();
1101-
for (const auto& entry : _searchIndex)
1102-
{
1103-
// TODO CARLOS: replace with fuzzy search
1104-
const auto& displayText = entry.DisplayText;
1105-
if (til::contains_linguistic_insensitive(displayText, queryText))
1193+
auto findMatchingResults = [&queryText](const std::vector<LocalizedIndexEntry>& searchIndex, std::vector<const LocalizedIndexEntry*>& filteredIndex) {
1194+
filteredIndex.clear();
1195+
for (const auto& entry : searchIndex)
11061196
{
1107-
filteredResults->push_back(&entry);
1197+
// TODO CARLOS: replace with fuzzy search
1198+
// Check for a match with DisplayText (i.e. "Globals_DefaultProfile/Header") and HelpText (i.e. "Globals_DefaultProfile/HelpText")
1199+
// in language neutral and current language
1200+
if (til::contains_linguistic_insensitive(entry.Entry->DisplayTextLocalized, queryText) ||
1201+
(entry.Entry->HelpTextLocalized.has_value() && til::contains_linguistic_insensitive(entry.Entry->HelpTextLocalized.value(), queryText)) ||
1202+
(entry.DisplayTextNeutral.has_value() && til::contains_linguistic_insensitive(entry.DisplayTextNeutral.value(), queryText)) ||
1203+
(entry.HelpTextNeutral.has_value() && til::contains_linguistic_insensitive(entry.HelpTextNeutral.value(), queryText)))
1204+
{
1205+
filteredIndex.push_back(&entry);
1206+
}
11081207
}
1109-
}
1208+
};
1209+
1210+
// build-time search index can be filtered and returned pretty much as-is
1211+
findMatchingResults(_searchIndex, *filteredResults);
1212+
1213+
// Profiles
1214+
findMatchingResults(_searchProfileIndex, _filteredSearchProfileIndex);
1215+
1216+
// New Tab Menu (Folder View)
1217+
findMatchingResults(_searchNTMFolderIndex, _filteredSearchNTMFolderIndex);
1218+
1219+
// Color schemes
1220+
findMatchingResults(_searchColorSchemeIndex, _filteredSearchColorSchemeIndex);
1221+
11101222
return _filteredSearchIndex.generation();
11111223
}
11121224

@@ -1123,22 +1235,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
11231235

11241236
// Navigate to the target page
11251237
const auto& indexEntry{ chosenResult->SearchIndexEntry() };
1126-
const auto& navigationParam{ indexEntry.NavigationParam };
1127-
if (navigationParam.try_as<hstring>())
1238+
const auto& navigationArg{ chosenResult->NavigationArg() };
1239+
const auto& subpage{ indexEntry.Entry->SubPage };
1240+
const auto& elementToFocus{ indexEntry.Entry->ElementName };
1241+
if (navigationArg.try_as<hstring>())
11281242
{
1129-
_Navigate(navigationParam.as<hstring>(), indexEntry.SubPage, indexEntry.ElementName);
1243+
_Navigate(navigationArg.as<hstring>(), subpage, elementToFocus);
11301244
}
1131-
else if (const auto profileVM = navigationParam.try_as<ProfileViewModel>())
1245+
else if (const auto profileVM = navigationArg.try_as<ProfileViewModel>())
11321246
{
1133-
_Navigate(*profileVM, indexEntry.SubPage, indexEntry.ElementName);
1247+
_Navigate(*profileVM, subpage, elementToFocus);
11341248
}
1135-
else if (const auto ntmEntryVM = navigationParam.try_as<NewTabMenuEntryViewModel>())
1249+
else if (const auto ntmEntryVM = navigationArg.try_as<NewTabMenuEntryViewModel>())
11361250
{
1137-
_Navigate(*ntmEntryVM, indexEntry.SubPage, indexEntry.ElementName);
1251+
_Navigate(*ntmEntryVM, subpage, elementToFocus);
11381252
}
1139-
else if (const auto extPkgVM = navigationParam.try_as<ExtensionPackageViewModel>())
1253+
else if (const auto extPkgVM = navigationArg.try_as<ExtensionPackageViewModel>())
11401254
{
1141-
_Navigate(*extPkgVM, indexEntry.SubPage, indexEntry.ElementName);
1255+
_Navigate(*extPkgVM, subpage, elementToFocus);
11421256
}
11431257
}
11441258
}
@@ -1150,54 +1264,94 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
11501264
// AutoSuggestBox will pass the chosen item to QuerySubmitted() via args.ChosenSuggestion()
11511265
}
11521266

1153-
void MainPage::_UpdateSearchIndex()
1267+
safe_void_coroutine MainPage::_UpdateSearchIndex()
11541268
{
1155-
_searchIndex = {};
1269+
co_await winrt::resume_background();
11561270

1157-
// TODO CARLOS: delay evaluating resources to here.
1158-
// - we also want to allow searching in English regardless or the selected language
1159-
// - we still want to only show the native language though
1160-
// - we should update the index to use USES_RESOURCE instead of RS_, then evaluate resources here
1271+
// These are the new index entries we are building.
1272+
// Don't actually modify the members until we're completely done here.
1273+
std::vector<LocalizedIndexEntry> localizedIndex;
1274+
std::vector<LocalizedIndexEntry> localizedProfileIndex;
1275+
std::vector<LocalizedIndexEntry> localizedNTMFolderIndex;
1276+
std::vector<LocalizedIndexEntry> localizedColorSchemeIndex;
1277+
1278+
// TODO CARLOS: actually use this
1279+
// copied from CommandPaletteItems.h
1280+
static bool shouldIncludeLanguageNeutralResources = [] {
1281+
try
1282+
{
1283+
const auto context{ winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::GetForViewIndependentUse() };
1284+
const auto qualifiers{ context.QualifierValues() };
1285+
if (const auto language{ qualifiers.TryLookup(L"language") })
1286+
{
1287+
return !til::starts_with_insensitive_ascii(*language, L"en-");
1288+
}
1289+
}
1290+
catch (...)
1291+
{
1292+
LOG_CAUGHT_EXCEPTION();
1293+
}
1294+
return false;
1295+
}();
11611296

1162-
const auto buildIndex = LoadBuildTimeIndex();
1163-
_searchIndex.reserve(buildIndex.size());
1164-
_searchIndex.insert(_searchIndex.end(), buildIndex.begin(), buildIndex.end());
1297+
const auto& buildIndex = LoadBuildTimeIndex();
1298+
localizedIndex.reserve(buildIndex.size());
1299+
for (const auto& entry : buildIndex)
1300+
{
1301+
// TODO CARLOS: properly populate LocalizedIndexEntry
1302+
LocalizedIndexEntry localizedEntry;
1303+
localizedEntry.Entry = &entry;
1304+
localizedIndex.push_back(localizedEntry);
1305+
}
11651306

11661307
// Load profiles
1167-
for (const auto& profile : _profileVMs)
1308+
const auto& profileIndex = LoadProfileIndex();
1309+
localizedProfileIndex.reserve(profileIndex.size());
1310+
for (const auto& entry : profileIndex)
11681311
{
1169-
const auto& profileIndex = LoadProfileIndex(profile);
1170-
_searchIndex.reserve(_searchIndex.size() + profileIndex.size());
1171-
_searchIndex.insert(_searchIndex.end(), profileIndex.begin(), profileIndex.end());
1312+
// TODO CARLOS: properly populate LocalizedIndexEntry
1313+
LocalizedIndexEntry localizedEntry;
1314+
localizedEntry.Entry = &entry;
1315+
localizedProfileIndex.push_back(localizedEntry);
11721316
}
11731317

11741318
// Load new tab menu
1175-
for (const auto& folderVM : get_self<implementation::NewTabMenuViewModel>(_newTabMenuPageVM)->FolderTreeFlatList())
1319+
const auto& ntmFolderIndex = LoadNTMFolderIndex();
1320+
localizedNTMFolderIndex.reserve(ntmFolderIndex.size());
1321+
for (const auto& entry : ntmFolderIndex)
11761322
{
1177-
const auto& folderIndex = LoadNTMFolderIndex(folderVM);
1178-
_searchIndex.reserve(_searchIndex.size() + folderIndex.size());
1179-
_searchIndex.insert(_searchIndex.end(), folderIndex.begin(), folderIndex.end());
1323+
// TODO CARLOS: properly populate LocalizedIndexEntry
1324+
LocalizedIndexEntry localizedEntry;
1325+
localizedEntry.Entry = &entry;
1326+
localizedNTMFolderIndex.push_back(localizedEntry);
11801327
}
11811328

1182-
// Load extensions
1183-
// TODO CARLOS: annoying that we have to load the extensions to build the index. Can we defer this until the user searches?
1184-
get_self<ExtensionsViewModel>(_extensionsVM)->LazyLoadExtensions();
1185-
for (const auto& extPkg : _extensionsVM.ExtensionPackages())
1186-
{
1187-
const auto& extPkgIndex = LoadExtensionIndex(extPkg);
1188-
_searchIndex.reserve(_searchIndex.size() + extPkgIndex.size());
1189-
_searchIndex.insert(_searchIndex.end(), extPkgIndex.begin(), extPkgIndex.end());
1190-
}
1329+
// Nothing to load for extensions.
1330+
// At query time, we'll search for matching extension names.
11911331

11921332
// Load color schemes
1193-
for (const auto& schemeVM : _colorSchemesPageVM.AllColorSchemes())
1333+
const auto& colorSchemesIndex = LoadColorSchemeIndex();
1334+
localizedColorSchemeIndex.reserve(colorSchemesIndex.size());
1335+
for (const auto& entry : colorSchemesIndex)
11941336
{
1195-
const auto& schemeIndex = LoadColorSchemeIndex(schemeVM.Name());
1196-
_searchIndex.reserve(_searchIndex.size() + schemeIndex.size());
1197-
_searchIndex.insert(_searchIndex.end(), schemeIndex.begin(), schemeIndex.end());
1337+
// TODO CARLOS: properly populate LocalizedIndexEntry
1338+
LocalizedIndexEntry localizedEntry;
1339+
localizedEntry.Entry = &entry;
1340+
localizedColorSchemeIndex.push_back(localizedEntry);
11981341
}
11991342

12001343
// Load actions
12011344
// TODO CARLOS: postpone until actions page is updated
1345+
1346+
_searchIndex = std::move(localizedIndex);
1347+
_searchProfileIndex = std::move(localizedProfileIndex);
1348+
_searchNTMFolderIndex = std::move(localizedNTMFolderIndex);
1349+
_searchColorSchemeIndex = std::move(localizedColorSchemeIndex);
1350+
}
1351+
1352+
const ScopedResourceLoader& EnglishOnlyResourceLoader() noexcept
1353+
{
1354+
static ScopedResourceLoader loader{ GetLibraryResourceLoader().WithQualifier(L"language", L"en-US") };
1355+
return loader;
12021356
}
12031357
}

0 commit comments

Comments
 (0)