Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions extensions/nerdfont-search/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 14 additions & 4 deletions extensions/nerdfont-search/src/filtering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,32 @@ function filterIconIndex({
fuseInstance,
searchText,
selectedPack,
packIndex,
}: {
iconIndex: IconIndex[];
fuseInstance: { search: (query: string) => Array<{ score?: number; item: IconIndex }> } | null;
fuseInstance: {
search: (query: string) => Array<{ score?: number; item: IconIndex }>;
} | null;
searchText: string;
selectedPack: string;
packIndex?: Map<string, IconIndex[]> | null;
}): IconIndex[] {
if (iconIndex.length === 0) {
return [];
}

if (searchText.length < 3) {
if (selectedPack === PACK_FILTER_ALL) {
return [];
return iconIndex.slice(0, SEARCH_RESULT_LIMIT);
}

if (packIndex) {
const packIcons = packIndex.get(selectedPack);
return packIcons ? packIcons.slice(0, SEARCH_RESULT_LIMIT) : [];
}
Comment on lines 37 to 45
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new behavior is described as “show all icons when search is empty”, but this branch runs for any searchText.length < 3 and also applies SEARCH_RESULT_LIMIT via slice(0, SEARCH_RESULT_LIMIT). That means 1–2 character queries will ignore the query and just show the default alphabetical list, and empty search will only show the first 200 icons—not “all” icons. Consider handling searchText.length === 0 separately from 1–2 characters, and clarify whether the limit should apply for the empty-search listing.

Copilot uses AI. Check for mistakes.

return iconIndex
.filter((icon) => icon.pack === selectedPack)
.sort((a, b) => a.displayName.localeCompare(b.displayName))
.slice(0, SEARCH_RESULT_LIMIT);
}

Expand All @@ -48,7 +56,9 @@ function filterIconIndex({
let searchResults = fuseInstance.search(searchText);

if (selectedPack !== PACK_FILTER_ALL) {
searchResults = searchResults.filter((result) => result.item.pack === selectedPack);
searchResults = searchResults.filter(
(result) => result.item.pack === selectedPack,
);
}

return sortFuseResultsByScoreThenId(searchResults)
Expand Down
58 changes: 29 additions & 29 deletions extensions/nerdfont-search/src/fuse-options.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
"keys": [
{
"name": "displayName",
"weight": 0.3
},
{
"name": "id",
"weight": 0.5
},
{
"name": "searchTokens",
"weight": 0.8
},
{
"name": "pack",
"weight": 1
}
],
"threshold": 0.4,
"location": 0,
"distance": 100,
"ignoreLocation": false,
"ignoreFieldNorm": false,
"fieldNormWeight": 1,
"minMatchCharLength": 2,
"shouldSort": true,
"includeScore": true,
"findAllMatches": false,
"useExtendedSearch": false
"keys": [
{
"name": "displayName",
"weight": 0.3
},
{
"name": "id",
"weight": 0.5
},
{
"name": "searchTokens",
"weight": 0.8
},
{
"name": "pack",
"weight": 1
}
],
"threshold": 0.4,
"location": 0,
"distance": 100,
"ignoreLocation": false,
"ignoreFieldNorm": false,
"fieldNormWeight": 1,
"minMatchCharLength": 2,
"shouldSort": true,
"includeScore": true,
"findAllMatches": false,
"useExtendedSearch": false
}
90 changes: 46 additions & 44 deletions extensions/nerdfont-search/src/hooks/useIconData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,56 @@ import {
ensureIconIndexLoaded,
getCachedIconIndex,
getFuseInstance,
getPackIndex,
type IconIndex,
} from "../icon-index-store";

export function useIconData() {
const [iconIndex, setIconIndex] = useState<IconIndex[]>(
() => getCachedIconIndex() ?? [],
);
const [isLoading, setIsLoading] = useState(getCachedIconIndex() === null);

useEffect(() => {
const cached = getCachedIconIndex();
if (cached) {
setIconIndex(cached);
setIsLoading(false);
return;
}

let cancelled = false;

setIsLoading(true);

ensureIconIndexLoaded()
.then((data) => {
if (cancelled) {
return;
}

setIconIndex(data);
setIsLoading(false);
})
.catch(() => {
if (cancelled) {
return;
}

setIsLoading(false);
});

return () => {
cancelled = true;
};
}, []);

return {
iconIndex,
isLoading,
fuseInstance: getFuseInstance(),
};
const [iconIndex, setIconIndex] = useState<IconIndex[]>(
() => getCachedIconIndex() ?? [],
);
const [isLoading, setIsLoading] = useState(getCachedIconIndex() === null);

useEffect(() => {
const cached = getCachedIconIndex();
if (cached) {
setIconIndex(cached);
setIsLoading(false);
return;
}

let cancelled = false;

setIsLoading(true);

ensureIconIndexLoaded()
.then((data) => {
if (cancelled) {
return;
}

setIconIndex(data);
setIsLoading(false);
})
.catch(() => {
if (cancelled) {
return;
}

setIsLoading(false);
});

return () => {
cancelled = true;
};
}, []);

return {
iconIndex,
isLoading,
fuseInstance: getFuseInstance(),
packIndex: getPackIndex(),
};
}

export type { IconIndex };
Loading
Loading