Skip to content

Commit 724b9ec

Browse files
committed
enhance(search): replace fuse with obsidian search
1 parent 4fed86d commit 724b9ec

14 files changed

Lines changed: 61 additions & 62 deletions

File tree

package-lock.json

Lines changed: 2 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
"dependencies": {
5050
"classnames": "2.5.1",
5151
"diff": "5.2.0",
52-
"fuse.js": "7.0.0",
5352
"lucide-svelte": "0.344.0",
5453
"monkey-around": "3.0.0",
5554
"nanoid": "5.0.6",

src/stores/view/default-view-state.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { ViewState } from 'src/stores/view/view-state-type';
33
export const defaultViewState = (): ViewState => ({
44
search: {
55
query: '',
6-
results: new Set(),
6+
results: new Map(),
77
searching: false,
88
showInput: false,
9-
fuzzySearch: false,
9+
fuzzySearch: true,
1010
showAllNodes: true,
1111
},
1212
ui: {

src/stores/view/reducers/search/set-search-query.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export type SetSearchQueryAction = {
99

1010
export const setSearchQuery = (state: ViewState, query: string) => {
1111
state.search.query = query;
12-
if (!query) state.search.results = new Set();
12+
if (!query) state.search.results = new Map();
1313
state.search.searching = query.length > 0;
1414
state.search = { ...state.search };
1515
};
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import { NodeId } from 'src/stores/document/document-state-type';
21
import { ViewState } from 'src/stores/view/view-state-type';
2+
import { NodeSearchResult } from 'src/stores/view/subscriptions/effects/document-search/document-search';
33

44
export type SetSearchResultsAction = {
55
type: 'SEARCH/SET_RESULTS';
66
payload: {
7-
results: NodeId[];
7+
results: Map<string, NodeSearchResult>;
88
};
99
};
1010

11-
export const setSearchResults = (state: ViewState, results: NodeId[]) => {
12-
state.search.results = new Set(results);
11+
export const setSearchResults = (
12+
state: ViewState,
13+
results: Map<string, NodeSearchResult>,
14+
) => {
15+
state.search.results = new Map(results);
1316
state.search.searching = false;
1417
state.search = { ...state.search };
1518
};
Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,41 @@
11
import { LineageView } from 'src/view/view';
2-
import { FuseResult } from 'fuse.js';
2+
import { debounce } from 'obsidian';
33

4-
const updateActiveNodeAfterSearch = (
4+
export const updateActiveNodeAfterSearch = (
55
view: LineageView,
6-
results: FuseResult<{ id: string; content: string }>[],
6+
results: string[],
77
) => {
8+
const activeNode = view.viewStore.getValue().document.activeNode;
89
const shouldUpdateActiveNode =
9-
results.length > 0 &&
10-
!results.find(
11-
(r) => r.item.id === view.viewStore.getValue().document.activeNode,
12-
);
10+
results.length > 0 && !results.find((r) => r === activeNode);
1311
if (shouldUpdateActiveNode) {
1412
view.viewStore.dispatch({
1513
type: 'view/set-active-node/search',
1614
payload: {
17-
id: results[0].item.id,
15+
id: results[0],
1816
},
1917
});
2018
}
2119
};
2220

23-
export const updateSearchResults = (view: LineageView) => {
21+
export const updateSearchResults = debounce((view: LineageView) => {
2422
const viewState = view.viewStore.getValue();
2523

2624
const query = viewState.search.query;
2725
if (!query) return;
28-
const search = view.documentSearch.search(query);
29-
const results = search.map((r) => r.item.id);
26+
const results = view.documentSearch.search(query);
3027
view.viewStore.dispatch({
3128
type: 'SEARCH/SET_RESULTS',
3229
payload: {
3330
results: results,
3431
},
3532
});
36-
// needed in cases where the structure of the document is updated while showing search results (dnd/moving branches)
37-
// in these cases, unless search results have changed, active node should be maintained
33+
3834
const newSearchResults = Array.from(results).sort().join('');
39-
const previousSearchResults = Array.from(viewState.search.results)
35+
const previousSearchResults = Array.from(viewState.search.results.keys())
4036
.sort()
4137
.join('');
4238
if (previousSearchResults !== newSearchResults) {
43-
updateActiveNodeAfterSearch(view, search);
39+
updateActiveNodeAfterSearch(view, Array.from(results.keys()));
4440
}
45-
};
41+
}, 350);

src/view/helpers/document-search.ts renamed to src/stores/view/subscriptions/effects/document-search/document-search.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,52 @@
1-
import Fuse from 'fuse.js';
21
import { LineageView } from 'src/view/view';
2+
import {
3+
prepareFuzzySearch,
4+
prepareSimpleSearch,
5+
SearchResult,
6+
} from 'obsidian';
7+
8+
type SearchItem = { id: string; content: string };
9+
10+
export type NodeSearchResult = SearchResult;
311

412
export class DocumentSearch {
513
constructor(private view: LineageView) {}
6-
private fuse: Fuse<{ id: string; content: string }> | null;
714
#searchTriggeredMinimap: boolean;
8-
15+
private index: SearchItem[] | null = null;
916
private updateIndex = () => {
1017
const documentState = this.view.documentStore.getValue();
11-
const viewState = this.view.viewStore.getValue();
12-
const items: { id: string; content: string }[] = [];
18+
this.index = [];
1319
for (const id of Object.keys(documentState.document.content)) {
1420
const content = documentState.document.content[id]?.content;
1521
if (content) {
16-
items.push({
22+
this.index.push({
1723
id,
1824
content,
1925
});
2026
}
2127
}
22-
this.fuse = new Fuse(items, {
23-
keys: ['content'],
24-
threshold: viewState.search.fuzzySearch ? 0.4 : 0.1,
25-
shouldSort: true,
26-
isCaseSensitive: false,
27-
ignoreLocation: true,
28-
});
2928
};
3029

3130
resetIndex = () => {
32-
this.fuse = null;
31+
this.index = null;
3332
};
3433

3534
search = (query: string) => {
36-
if (!this.fuse) {
35+
if (!this.index || this.index.length === 0) {
3736
this.updateIndex();
3837
}
39-
return this.fuse!.search(query);
38+
const viewState = this.view.viewStore.getValue();
39+
const searchUtil = viewState.search.fuzzySearch
40+
? prepareFuzzySearch
41+
: prepareSimpleSearch;
42+
const results: Map<string, NodeSearchResult> = new Map();
43+
for (const item of this.index!) {
44+
const result = searchUtil(query)(item.content);
45+
if (result) {
46+
results.set(item.id, result);
47+
}
48+
}
49+
return results;
4050
};
4151

4252
get searchTriggeredMinimap() {

src/stores/view/view-state-type.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
import {
2-
NavigationHistory,
3-
NodeId,
4-
} from 'src/stores/document/document-state-type';
1+
import { NavigationHistory } from 'src/stores/document/document-state-type';
52
import {
63
ActiveBranch,
74
DNDState,
85
EditingState,
96
} from 'src/stores/view/default-view-state';
107
import { ConflictingHotkeys } from 'src/obsidian/helpers/get-used-hotkeys';
118
import { NodeStyle } from 'src/stores/settings/types/style-rules-types';
9+
import { NodeSearchResult } from 'src/stores/view/subscriptions/effects/document-search/document-search';
1210

1311
export type ActiveNodesOfColumn = {
1412
[columnId: string]: {
@@ -39,7 +37,7 @@ export type RecentNodes = {
3937
export type ViewState = {
4038
search: {
4139
query: string;
42-
results: Set<NodeId>;
40+
results: Map<string, NodeSearchResult>;
4341
searching: boolean;
4442
showInput: boolean;
4543
fuzzySearch: boolean;

src/view/components/container/column/column.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import { EditingState } from 'src/stores/view/default-view-state';
66
import { PendingDocumentConfirmation } from 'src/stores/view/view-state-type';
77
import { NodeStyle } from 'src/stores/settings/types/style-rules-types';
8+
import { NodeSearchResult } from 'src/stores/view/subscriptions/effects/document-search/document-search';
89
910
export let columnId: string;
1011
export let activeChildGroups: Set<string>;
@@ -17,7 +18,7 @@
1718
export let pendingConfirmation: PendingDocumentConfirmation;
1819
export let showAllNodes: boolean;
1920
export let searchQuery: string;
20-
export let searchResults: Set<string>;
21+
export let searchResults: Map<string,NodeSearchResult>;
2122
export let pinnedNodes: Set<string>;
2223
export let allDndNodes: Set<string>;
2324
export let groupParentIds: Set<string>;

src/view/components/container/column/components/group/group.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { PendingDocumentConfirmation } from 'src/stores/view/view-state-type';
88
import { nodesStore, singleColumnNodesStore } from 'src/stores/document/derived/nodes-store';
99
import { NodeStyle } from 'src/stores/settings/types/style-rules-types';
10+
import { NodeSearchResult } from 'src/stores/view/subscriptions/effects/document-search/document-search';
1011
1112
export let groupId: string;
1213
export let columnId: string;
@@ -18,7 +19,7 @@
1819
export let editedNodeState: EditingState;
1920
export let pendingConfirmation: PendingDocumentConfirmation;
2021
export let searchQuery: string;
21-
export let searchResults: Set<string>;
22+
export let searchResults: Map<string,NodeSearchResult>;
2223
export let showAllNodes: boolean;
2324
export let pinnedNodes: Set<string>;
2425
export let searching: boolean;

0 commit comments

Comments
 (0)