@lapis-notes/search 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +1 -1
- package/dist/native-search.d.ts +5 -0
- package/dist/native-search.js +24 -0
- package/dist/search-history-versions.svelte +197 -0
- package/dist/search-history-versions.svelte.d.ts +8 -0
- package/dist/search-manager.d.ts +3 -0
- package/dist/search-manager.js +72 -7
- package/dist/search-panel.css +103 -0
- package/dist/search-panel.svelte +343 -41
- package/dist/search-panel.svelte.d.ts +8 -1
- package/dist/search-plugin.d.ts +7 -1
- package/dist/search-plugin.js +97 -15
- package/dist/search-provider-controller.d.ts +25 -0
- package/dist/search-provider-controller.js +157 -0
- package/dist/search-provider-groups.d.ts +14 -0
- package/dist/search-provider-groups.js +60 -0
- package/dist/search-settings-observer.d.ts +4 -0
- package/dist/search-settings-observer.js +10 -0
- package/dist/search-settings-tab.js +2 -2
- package/dist/search-tool-result.css +2 -7
- package/dist/search-tool-result.svelte +9 -2
- package/dist/search-view.d.ts +5 -1
- package/dist/search-view.js +32 -4
- package/manifest.json +2 -2
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# Search changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#54](https://github.com/lapismd/lapis-plugins/pull/54) [`91d0014`](https://github.com/lapismd/lapis-plugins/commit/91d001499930e7c4ea2c9ea622e3f5ed2d956ab3) Thanks [@lapismd-dependency-bot](https://github.com/apps/lapismd-dependency-bot)! - Refresh first-party Lapis dependencies to the published versions recorded in this pull request.
|
|
8
|
+
|
|
9
|
+
## 0.1.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`d27467e`](https://github.com/lapismd/lapis-plugins/commit/d27467ee80c273011b7eb6ae792fa8e0330a11c1) Thanks [@stevejuma](https://github.com/stevejuma)! - Align shared presentation dependencies with the Design Core 0.6 public boundary used by current Notes hosts.
|
|
14
|
+
|
|
15
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`0ed680e`](https://github.com/lapismd/lapis-plugins/commit/0ed680ef409b9bb179312d1b06cee02af56b3e8a) Thanks [@stevejuma](https://github.com/stevejuma)! - Use an explicitly selected native indexing observer for Search configuration,
|
|
16
|
+
refresh and progress while preserving standalone browser processing. Keep view
|
|
17
|
+
teardown passive, fence late continuations and recreate the manager when the
|
|
18
|
+
plugin is enabled again.
|
|
19
|
+
|
|
20
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`56b5d6c`](https://github.com/lapismd/lapis-plugins/commit/56b5d6c1a016ef9bca43703b5fecf57f8234d1af) Thanks [@stevejuma](https://github.com/stevejuma)! - Consume published Design Core 0.4.0 with prepared browser CSS and bundled font assets through normal npm ranges.
|
|
21
|
+
|
|
22
|
+
Restore Bases picker input/list accessibility relationships and name property actions.
|
|
23
|
+
|
|
24
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`c9febb1`](https://github.com/lapismd/lapis-plugins/commit/c9febb1c8b431db30ecdcf7507cfff8f727bc4ed) Thanks [@stevejuma](https://github.com/stevejuma)! - Consume the published Notes next packages, Mira 0.1.2, and Design Core 0.7.0 through the existing semver floors. Markdown dependents accept ^0.2.0. History keeps its public repository entrypoints, and Bases keeps the file-icon contract on API 0.2.0.
|
|
25
|
+
|
|
26
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`d463ee8`](https://github.com/lapismd/lapis-plugins/commit/d463ee8c5b48ee0f3a8992c7394f48124fb2cc1c) Thanks [@stevejuma](https://github.com/stevejuma)! - Send every Search command, background-indexing, settings-recovery and
|
|
27
|
+
copy-feedback notice through the explicitly owned App so a concurrent
|
|
28
|
+
compatibility host cannot receive delayed errors.
|
|
29
|
+
|
|
30
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`5bb36e5`](https://github.com/lapismd/lapis-plugins/commit/5bb36e5e01b7e6fb928955edc41426c12c4e5d55) Thanks [@stevejuma](https://github.com/stevejuma)! - Await Search panel teardown before the owning view finishes closing.
|
|
31
|
+
|
|
32
|
+
- [#28](https://github.com/lapismd/lapis-plugins/pull/28) [`c2d1149`](https://github.com/lapismd/lapis-plugins/commit/c2d11499114ec92a2c168c4ec9a1efd6cbc01eee) Thanks [@stevejuma](https://github.com/stevejuma)! - Refresh Search controls after settings recovery and preserve recovered values
|
|
33
|
+
when saving another preference. Reconcile recovered native indexing settings
|
|
34
|
+
through the existing host controls.
|
|
35
|
+
|
|
3
36
|
## 0.1.3
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Register the exported plugin class in the application's `PluginProfile`. Import
|
|
|
13
13
|
registration so the host owns its lifecycle.
|
|
14
14
|
|
|
15
15
|
The runtime plugin ID is `search`. A matching signed
|
|
16
|
-
`search-0.1.
|
|
16
|
+
`search-0.1.5.lapis-plugin` archive is attached to the
|
|
17
17
|
package-scoped GitHub release for manual or registry installation.
|
|
18
18
|
|
|
19
19
|
See the [repository README](https://github.com/lapismd/lapis-plugins#readme) for
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { App, NativeBackgroundIndexingObserver } from "@lapis-notes/api";
|
|
2
|
+
import type { SearchPluginSettings } from "./search-settings";
|
|
3
|
+
export declare function hasNativeSearch(app: App): boolean;
|
|
4
|
+
export declare function nativeSearch(app: App): NativeBackgroundIndexingObserver;
|
|
5
|
+
export declare function configureNativeSearch(app: App, settings: SearchPluginSettings): Promise<NativeBackgroundIndexingObserver>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function hasNativeSearch(app) {
|
|
2
|
+
return Boolean(app.session?.backgroundIndexing);
|
|
3
|
+
}
|
|
4
|
+
export function nativeSearch(app) {
|
|
5
|
+
const observer = app.backgroundIndexing;
|
|
6
|
+
if (!observer)
|
|
7
|
+
throw new Error("The selected native Search observer is unavailable");
|
|
8
|
+
return observer;
|
|
9
|
+
}
|
|
10
|
+
export async function configureNativeSearch(app, settings) {
|
|
11
|
+
const observer = nativeSearch(app);
|
|
12
|
+
const contribution = await observer.selectSearch({
|
|
13
|
+
providers: app.searchDocumentProviders.getAll().map((provider) => ({
|
|
14
|
+
provider_id: provider.id,
|
|
15
|
+
version: provider.version ?? "1",
|
|
16
|
+
priority: provider.priority ?? 0,
|
|
17
|
+
})),
|
|
18
|
+
chunking: { ...settings.chunking },
|
|
19
|
+
});
|
|
20
|
+
if (contribution.placement !== "native") {
|
|
21
|
+
throw new Error(contribution.message ?? "Native Search cannot execute this provider");
|
|
22
|
+
}
|
|
23
|
+
return observer;
|
|
24
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Collapsible from "@lapismd/design-core/shadcn/collapsible";
|
|
3
|
+
import * as Sidebar from "@lapismd/design-core/shadcn/sidebar";
|
|
4
|
+
import { Badge } from "@lapismd/design-core/shadcn/badge";
|
|
5
|
+
import { Button } from "@lapismd/design-core/shadcn/button";
|
|
6
|
+
import ChevronUp from "@lucide/svelte/icons/chevron-up";
|
|
7
|
+
import ChevronDown from "@lucide/svelte/icons/chevron-down";
|
|
8
|
+
import ChevronRight from "@lucide/svelte/icons/chevron-right";
|
|
9
|
+
import type {
|
|
10
|
+
SearchProviderHit,
|
|
11
|
+
SearchProviderMatch,
|
|
12
|
+
SearchResultProvider,
|
|
13
|
+
} from "@lapis-notes/api";
|
|
14
|
+
import type { ProviderVersion } from "./search-provider-groups";
|
|
15
|
+
import HighlightedText from "./highlighted-text.svelte";
|
|
16
|
+
import { onDestroy } from "svelte";
|
|
17
|
+
const treeId = $props.id();
|
|
18
|
+
let {
|
|
19
|
+
versions,
|
|
20
|
+
report,
|
|
21
|
+
}: { versions: ProviderVersion[]; report(error: unknown): void } = $props();
|
|
22
|
+
let expanded = $state<Record<string, boolean>>({});
|
|
23
|
+
let contexts = $state<Record<string, SearchProviderMatch>>({});
|
|
24
|
+
let loading = $state<Record<string, boolean>>({});
|
|
25
|
+
const abort = new AbortController();
|
|
26
|
+
onDestroy(() => abort.abort());
|
|
27
|
+
const key = (provider: SearchResultProvider, hit: SearchProviderHit) =>
|
|
28
|
+
`${provider.id}/${hit.id}`;
|
|
29
|
+
async function open(
|
|
30
|
+
provider: SearchResultProvider,
|
|
31
|
+
hit: SearchProviderHit,
|
|
32
|
+
match?: SearchProviderMatch,
|
|
33
|
+
) {
|
|
34
|
+
try {
|
|
35
|
+
await provider.activate(hit, match);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
report(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function context(
|
|
41
|
+
provider: SearchResultProvider,
|
|
42
|
+
hit: SearchProviderHit,
|
|
43
|
+
match: SearchProviderMatch,
|
|
44
|
+
direction: "before" | "after",
|
|
45
|
+
) {
|
|
46
|
+
if (!provider.expand) return;
|
|
47
|
+
const id = `${key(provider, hit)}/${match.id}`;
|
|
48
|
+
loading[id] = true;
|
|
49
|
+
try {
|
|
50
|
+
const next = await provider.expand(hit, match, direction, abort.signal);
|
|
51
|
+
if (!abort.signal.aborted) contexts[id] = next;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (!abort.signal.aborted) report(error);
|
|
54
|
+
} finally {
|
|
55
|
+
if (!abort.signal.aborted) loading[id] = false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<Sidebar.MenuSub role="group" class="search-panel__history-list">
|
|
61
|
+
{#each versions as { provider, hit }, index (`${provider.id}/${hit.id}`)}
|
|
62
|
+
{@const id = key(provider, hit)}
|
|
63
|
+
<Sidebar.MenuSubItem
|
|
64
|
+
role="treeitem"
|
|
65
|
+
aria-selected="false"
|
|
66
|
+
aria-level={2}
|
|
67
|
+
aria-expanded={expanded[id] ?? false}
|
|
68
|
+
>
|
|
69
|
+
<Collapsible.Root
|
|
70
|
+
open={expanded[id] ?? false}
|
|
71
|
+
onOpenChange={(value) => (expanded[id] = value)}
|
|
72
|
+
>
|
|
73
|
+
<Collapsible.Trigger
|
|
74
|
+
class="search-panel__history-version"
|
|
75
|
+
id={`${treeId}-${index}-label`}
|
|
76
|
+
aria-label={`History ${hit.version?.label ?? hit.title}${hit.timestamp ? ` ${new Date(hit.timestamp).toLocaleDateString()}` : ""}`}
|
|
77
|
+
aria-expanded={expanded[id] ?? false}
|
|
78
|
+
onkeydown={(event) => {
|
|
79
|
+
if (event.key === "ArrowRight" || event.key === "ArrowLeft") {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
expanded[id] = event.key === "ArrowRight";
|
|
82
|
+
}
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<ChevronRight class="search-panel__disclosure" aria-hidden="true" />
|
|
86
|
+
<Badge variant="outline">History</Badge>
|
|
87
|
+
<span class="search-panel__history-label"
|
|
88
|
+
>{hit.version?.label ?? hit.title}</span
|
|
89
|
+
>
|
|
90
|
+
{#if hit.timestamp}<time
|
|
91
|
+
datetime={new Date(hit.timestamp).toISOString()}
|
|
92
|
+
>{new Date(hit.timestamp).toLocaleDateString()}</time
|
|
93
|
+
>{/if}
|
|
94
|
+
</Collapsible.Trigger>
|
|
95
|
+
<Collapsible.Content
|
|
96
|
+
class="search-panel__history-content"
|
|
97
|
+
role="group"
|
|
98
|
+
id={`${treeId}-${index}`}
|
|
99
|
+
>
|
|
100
|
+
<div class="search-panel__history-details">
|
|
101
|
+
<Button
|
|
102
|
+
variant="ghost"
|
|
103
|
+
size="sm"
|
|
104
|
+
onclick={() => open(provider, hit)}
|
|
105
|
+
aria-label={`Open saved version ${hit.version?.label ?? hit.title}: ${hit.version?.author ?? provider.label}${hit.version ? ` · ${hit.version.id.slice(0, 12)}` : ""}`}
|
|
106
|
+
>
|
|
107
|
+
{hit.version?.author ?? provider.label}{hit.version
|
|
108
|
+
? ` · ${hit.version.id.slice(0, 12)}`
|
|
109
|
+
: ""}
|
|
110
|
+
</Button>
|
|
111
|
+
{#each hit.badges ?? [] as badge}<Badge variant="outline"
|
|
112
|
+
>{badge}</Badge
|
|
113
|
+
>{/each}
|
|
114
|
+
{#if (hit.version?.occurrences ?? 0) > 1}<Badge variant="outline"
|
|
115
|
+
>{hit.version?.occurrences} checkpoints</Badge
|
|
116
|
+
>{/if}
|
|
117
|
+
</div>
|
|
118
|
+
{#if hit.version?.references && hit.version.references.length > 1}
|
|
119
|
+
<div
|
|
120
|
+
class="search-panel__history-details"
|
|
121
|
+
aria-label="Matching checkpoints"
|
|
122
|
+
>
|
|
123
|
+
{#each hit.version.references as reference (reference.id)}
|
|
124
|
+
<Button
|
|
125
|
+
variant="ghost"
|
|
126
|
+
size="sm"
|
|
127
|
+
onclick={() =>
|
|
128
|
+
open(provider, { ...hit, target: reference.target })}
|
|
129
|
+
>{reference.id.slice(0, 12)} · {new Date(
|
|
130
|
+
reference.timestamp,
|
|
131
|
+
).toLocaleDateString()}</Button
|
|
132
|
+
>
|
|
133
|
+
{/each}
|
|
134
|
+
</div>
|
|
135
|
+
{/if}
|
|
136
|
+
<Sidebar.MenuSub role="group" class="search-panel__history-matches">
|
|
137
|
+
{#each hit.matches as original (original.id)}
|
|
138
|
+
{@const matchId = `${id}/${original.id}`}
|
|
139
|
+
{@const match = contexts[matchId] ?? original}
|
|
140
|
+
<Sidebar.MenuSubItem role="none">
|
|
141
|
+
<div
|
|
142
|
+
class="search-panel__match-shell"
|
|
143
|
+
role="treeitem"
|
|
144
|
+
aria-selected="false"
|
|
145
|
+
aria-level={3}
|
|
146
|
+
aria-label={`${match.text} ${match.field}`}
|
|
147
|
+
tabindex={0}
|
|
148
|
+
onclick={() => open(provider, hit, match)}
|
|
149
|
+
onkeydown={(event) => {
|
|
150
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
151
|
+
event.preventDefault();
|
|
152
|
+
void open(provider, hit, match);
|
|
153
|
+
}
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
{#if match.context && provider.expand}<Button
|
|
157
|
+
size="icon-xs"
|
|
158
|
+
variant="ghost"
|
|
159
|
+
aria-label="Show more context before this saved match"
|
|
160
|
+
disabled={loading[matchId]}
|
|
161
|
+
onclick={(event) => {
|
|
162
|
+
event.stopPropagation();
|
|
163
|
+
void context(provider, hit, match, "before");
|
|
164
|
+
}}><ChevronUp aria-hidden="true" /></Button
|
|
165
|
+
>{/if}
|
|
166
|
+
<div class="search-panel__match">
|
|
167
|
+
<span class="search-panel__match-text"
|
|
168
|
+
><HighlightedText
|
|
169
|
+
text={match.text}
|
|
170
|
+
ranges={match.ranges}
|
|
171
|
+
/></span
|
|
172
|
+
>
|
|
173
|
+
<span class="search-panel__match-meta"
|
|
174
|
+
><Badge variant="outline" class="search-panel__match-key"
|
|
175
|
+
>{match.field}</Badge
|
|
176
|
+
></span
|
|
177
|
+
>
|
|
178
|
+
</div>
|
|
179
|
+
{#if match.context && provider.expand}<Button
|
|
180
|
+
size="icon-xs"
|
|
181
|
+
variant="ghost"
|
|
182
|
+
aria-label="Show more context after this saved match"
|
|
183
|
+
disabled={loading[matchId]}
|
|
184
|
+
onclick={(event) => {
|
|
185
|
+
event.stopPropagation();
|
|
186
|
+
void context(provider, hit, match, "after");
|
|
187
|
+
}}><ChevronDown aria-hidden="true" /></Button
|
|
188
|
+
>{/if}
|
|
189
|
+
</div>
|
|
190
|
+
</Sidebar.MenuSubItem>
|
|
191
|
+
{/each}
|
|
192
|
+
</Sidebar.MenuSub>
|
|
193
|
+
</Collapsible.Content>
|
|
194
|
+
</Collapsible.Root>
|
|
195
|
+
</Sidebar.MenuSubItem>
|
|
196
|
+
{/each}
|
|
197
|
+
</Sidebar.MenuSub>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ProviderVersion } from "./search-provider-groups";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
versions: ProviderVersion[];
|
|
4
|
+
report(error: unknown): void;
|
|
5
|
+
};
|
|
6
|
+
declare const SearchHistoryVersions: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type SearchHistoryVersions = ReturnType<typeof SearchHistoryVersions>;
|
|
8
|
+
export default SearchHistoryVersions;
|
package/dist/search-manager.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export interface SearchQueryResult {
|
|
|
44
44
|
export declare class SearchManager {
|
|
45
45
|
readonly app: App;
|
|
46
46
|
private readonly getSettings;
|
|
47
|
+
private observedNativeRefreshActive;
|
|
47
48
|
private refreshPromise;
|
|
48
49
|
private queuedRefreshReason;
|
|
49
50
|
private refreshState;
|
|
@@ -71,6 +72,8 @@ export declare class SearchManager {
|
|
|
71
72
|
private runRefreshQueue;
|
|
72
73
|
trackChanges(): () => void;
|
|
73
74
|
dispose(): Promise<void>;
|
|
75
|
+
configureIndexing(): Promise<void>;
|
|
76
|
+
private refreshNative;
|
|
74
77
|
private processFile;
|
|
75
78
|
private projectionSignature;
|
|
76
79
|
private currentReconcileFingerprint;
|
package/dist/search-manager.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { debounce, md5, } from "@lapis-notes/api";
|
|
2
2
|
import { DEFAULT_SEARCH_SETTINGS, } from "./search-settings";
|
|
3
|
+
import { configureNativeSearch, hasNativeSearch, nativeSearch, } from "./native-search";
|
|
3
4
|
const REACTIVE_INDEX_DELAY_MS = 75;
|
|
4
5
|
const SEARCH_RECONCILE_CHECKPOINT_KEY = "search.reconcile-checkpoint.v1";
|
|
5
6
|
const SEARCH_RECONCILE_CHECKPOINT_VERSION = 1;
|
|
@@ -80,6 +81,7 @@ function sourceMetadata(cache, settings, source, manifest) {
|
|
|
80
81
|
export class SearchManager {
|
|
81
82
|
app;
|
|
82
83
|
getSettings;
|
|
84
|
+
observedNativeRefreshActive = false;
|
|
83
85
|
refreshPromise = null;
|
|
84
86
|
queuedRefreshReason = null;
|
|
85
87
|
refreshState = {
|
|
@@ -113,6 +115,10 @@ export class SearchManager {
|
|
|
113
115
|
}
|
|
114
116
|
}
|
|
115
117
|
async processChange(file, content, cache) {
|
|
118
|
+
if (hasNativeSearch(this.app)) {
|
|
119
|
+
nativeSearch(this.app);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
116
122
|
const provider = this.app.searchDocumentProviders.resolve(file);
|
|
117
123
|
if (!provider) {
|
|
118
124
|
await this.processDelete(file);
|
|
@@ -159,6 +165,10 @@ export class SearchManager {
|
|
|
159
165
|
});
|
|
160
166
|
}
|
|
161
167
|
async processDelete(file) {
|
|
168
|
+
if (hasNativeSearch(this.app)) {
|
|
169
|
+
nativeSearch(this.app);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
162
172
|
await this.app.appDatabase.deleteSearchDocument(typeof file === "string" ? file : file.path);
|
|
163
173
|
}
|
|
164
174
|
async query(params) {
|
|
@@ -211,7 +221,9 @@ export class SearchManager {
|
|
|
211
221
|
span.setAttribute("search.result.count", result.count);
|
|
212
222
|
span.setAttribute("search.path_prefix", Boolean(params.pathPrefix));
|
|
213
223
|
span.setAttribute("search.source_provider.count", params.sourceProviderIds?.length ?? 0);
|
|
214
|
-
span.setAttribute("search.reconcile.active", this.
|
|
224
|
+
span.setAttribute("search.reconcile.active", hasNativeSearch(this.app)
|
|
225
|
+
? this.observedNativeRefreshActive
|
|
226
|
+
: this.refreshState.active);
|
|
215
227
|
return result;
|
|
216
228
|
}, {
|
|
217
229
|
attributes: {
|
|
@@ -220,26 +232,42 @@ export class SearchManager {
|
|
|
220
232
|
});
|
|
221
233
|
}
|
|
222
234
|
async getStatus() {
|
|
223
|
-
const
|
|
235
|
+
const selected = hasNativeSearch(this.app);
|
|
236
|
+
const [provider, runtime, stats, native] = await Promise.all([
|
|
224
237
|
this.app.appDatabase.getSearchEmbeddingProvider(),
|
|
225
238
|
this.app.appDatabase.getSearchEmbeddingRuntimeStatus(),
|
|
226
239
|
this.app.appDatabase.getSearchIndexStats(),
|
|
240
|
+
selected ? nativeSearch(this.app).getStatus() : null,
|
|
227
241
|
]);
|
|
242
|
+
const nativeRefreshing = Boolean(native && (native.active || native.pending > 0));
|
|
243
|
+
if (selected)
|
|
244
|
+
this.observedNativeRefreshActive = nativeRefreshing;
|
|
228
245
|
return {
|
|
229
246
|
backendKind: this.app.appDatabase.kind,
|
|
230
247
|
provider,
|
|
231
248
|
runtime,
|
|
232
249
|
...stats,
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
lastError: native?.error ?? stats.lastError,
|
|
251
|
+
isRefreshing: selected ? nativeRefreshing : this.refreshState.active,
|
|
252
|
+
refreshReason: selected
|
|
253
|
+
? nativeRefreshing
|
|
254
|
+
? (this.refreshState.reason ?? "native-indexing")
|
|
255
|
+
: null
|
|
256
|
+
: this.refreshState.reason,
|
|
235
257
|
refreshProgress: {
|
|
236
|
-
processed:
|
|
237
|
-
|
|
258
|
+
processed: selected
|
|
259
|
+
? (native?.processed ?? 0)
|
|
260
|
+
: this.refreshState.processed,
|
|
261
|
+
total: selected ? (native?.total ?? 0) : this.refreshState.total,
|
|
238
262
|
},
|
|
239
|
-
refreshedAt:
|
|
263
|
+
refreshedAt: selected
|
|
264
|
+
? (native?.completed_at ?? null)
|
|
265
|
+
: this.refreshState.refreshedAt,
|
|
240
266
|
};
|
|
241
267
|
}
|
|
242
268
|
refreshFromVault(reason = "manual-refresh") {
|
|
269
|
+
if (hasNativeSearch(this.app))
|
|
270
|
+
return this.refreshNative(reason);
|
|
243
271
|
this.queuedRefreshReason = reason;
|
|
244
272
|
this.refreshPromise ??= this.runRefreshQueue().finally(() => {
|
|
245
273
|
this.refreshPromise = null;
|
|
@@ -247,6 +275,8 @@ export class SearchManager {
|
|
|
247
275
|
return this.refreshPromise;
|
|
248
276
|
}
|
|
249
277
|
async reconcileStartup() {
|
|
278
|
+
if (hasNativeSearch(this.app))
|
|
279
|
+
return this.refreshNative("startup");
|
|
250
280
|
const execute = async (setCheckpoint) => {
|
|
251
281
|
const initialGeneration = this.sourceGeneration;
|
|
252
282
|
let status;
|
|
@@ -294,6 +324,10 @@ export class SearchManager {
|
|
|
294
324
|
return status ?? this.getStatus();
|
|
295
325
|
}
|
|
296
326
|
trackChanges() {
|
|
327
|
+
if (hasNativeSearch(this.app)) {
|
|
328
|
+
nativeSearch(this.app);
|
|
329
|
+
return () => { };
|
|
330
|
+
}
|
|
297
331
|
const changed = this.app.metadataCache.on("changed", (file, content, cache) => {
|
|
298
332
|
if (!this.app.searchDocumentProviders.resolve(file))
|
|
299
333
|
return;
|
|
@@ -378,6 +412,12 @@ export class SearchManager {
|
|
|
378
412
|
if (this.disposed)
|
|
379
413
|
return;
|
|
380
414
|
this.flushQueuedChanges.cancel();
|
|
415
|
+
if (hasNativeSearch(this.app)) {
|
|
416
|
+
this.disposed = true;
|
|
417
|
+
this.queuedChanges.clear();
|
|
418
|
+
this.queuedDeletes.clear();
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
381
421
|
if (this.queuedChanges.size || this.queuedDeletes.size) {
|
|
382
422
|
await this.drainQueuedChanges();
|
|
383
423
|
}
|
|
@@ -391,6 +431,31 @@ export class SearchManager {
|
|
|
391
431
|
this.queuedChanges.clear();
|
|
392
432
|
this.queuedDeletes.clear();
|
|
393
433
|
}
|
|
434
|
+
async configureIndexing() {
|
|
435
|
+
if (this.disposed)
|
|
436
|
+
return;
|
|
437
|
+
if (hasNativeSearch(this.app))
|
|
438
|
+
await configureNativeSearch(this.app, this.getSettings());
|
|
439
|
+
}
|
|
440
|
+
async refreshNative(reason) {
|
|
441
|
+
if (this.disposed)
|
|
442
|
+
throw new Error("Search manager is disposed");
|
|
443
|
+
const previous = await this.getStatus();
|
|
444
|
+
if (this.disposed)
|
|
445
|
+
return previous;
|
|
446
|
+
const observer = await configureNativeSearch(this.app, this.getSettings());
|
|
447
|
+
if (this.disposed || observer.detached)
|
|
448
|
+
return previous;
|
|
449
|
+
this.refreshState.reason = reason;
|
|
450
|
+
await observer.refresh(reason.includes("rebuild"), {
|
|
451
|
+
title: "Refreshing search index",
|
|
452
|
+
source: "Search",
|
|
453
|
+
readyMessage: "Search index ready",
|
|
454
|
+
});
|
|
455
|
+
if (this.disposed || observer.detached)
|
|
456
|
+
return previous;
|
|
457
|
+
return this.getStatus();
|
|
458
|
+
}
|
|
394
459
|
async processFile(file) {
|
|
395
460
|
if (!this.app.searchDocumentProviders.resolve(file)) {
|
|
396
461
|
await this.processDelete(file);
|
package/dist/search-panel.css
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
color: var(--ui-workspace-view-foreground, inherit);
|
|
20
20
|
background: var(--ui-workspace-view-background, transparent);
|
|
21
21
|
font: inherit;
|
|
22
|
+
container: search-panel / inline-size;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
.search-panel__chrome {
|
|
@@ -92,6 +93,18 @@
|
|
|
92
93
|
white-space: nowrap;
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
@container search-panel (max-width: 24rem) {
|
|
97
|
+
.search-panel__sort {
|
|
98
|
+
width: 2rem;
|
|
99
|
+
flex: 0 0 auto;
|
|
100
|
+
padding-inline: 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.search-panel__sort-label {
|
|
104
|
+
display: none;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
.search-panel__sort-popover {
|
|
96
109
|
display: grid;
|
|
97
110
|
width: 15rem;
|
|
@@ -458,3 +471,93 @@
|
|
|
458
471
|
font-size: 0.8125rem;
|
|
459
472
|
text-align: center;
|
|
460
473
|
}
|
|
474
|
+
|
|
475
|
+
.search-panel__source {
|
|
476
|
+
margin-top: 0.5rem;
|
|
477
|
+
}
|
|
478
|
+
.search-panel__history-version {
|
|
479
|
+
display: grid;
|
|
480
|
+
grid-template-columns: 0.875rem auto minmax(0, 1fr) auto;
|
|
481
|
+
align-items: center;
|
|
482
|
+
gap: 0.375rem;
|
|
483
|
+
width: 100%;
|
|
484
|
+
min-width: 0;
|
|
485
|
+
padding: 0.375rem 0.5rem;
|
|
486
|
+
color: inherit;
|
|
487
|
+
font: inherit;
|
|
488
|
+
font-size: 0.8125rem;
|
|
489
|
+
line-height: 1.25rem;
|
|
490
|
+
background: transparent;
|
|
491
|
+
border: 0;
|
|
492
|
+
text-align: left;
|
|
493
|
+
border-radius: 0.25rem;
|
|
494
|
+
}
|
|
495
|
+
.search-panel__history-list,
|
|
496
|
+
.search-panel__history-matches {
|
|
497
|
+
display: grid;
|
|
498
|
+
gap: 0.125rem;
|
|
499
|
+
width: 100%;
|
|
500
|
+
min-width: 0;
|
|
501
|
+
margin: 0;
|
|
502
|
+
padding: 0;
|
|
503
|
+
border: 0;
|
|
504
|
+
list-style: none;
|
|
505
|
+
}
|
|
506
|
+
.search-panel__history-version > svg {
|
|
507
|
+
width: 0.875rem;
|
|
508
|
+
height: 0.875rem;
|
|
509
|
+
}
|
|
510
|
+
.search-panel__history-version[aria-expanded="true"] .search-panel__disclosure {
|
|
511
|
+
transform: rotate(90deg);
|
|
512
|
+
}
|
|
513
|
+
.search-panel__history-content {
|
|
514
|
+
padding: 0.125rem 0.5rem 0.5rem 1.375rem;
|
|
515
|
+
}
|
|
516
|
+
.search-panel__history-version:hover {
|
|
517
|
+
background: var(
|
|
518
|
+
--ui-workspace-hover,
|
|
519
|
+
color-mix(in srgb, currentColor 8%, transparent)
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
.search-panel__history-label {
|
|
523
|
+
flex: 1;
|
|
524
|
+
min-width: 0;
|
|
525
|
+
overflow: hidden;
|
|
526
|
+
text-overflow: ellipsis;
|
|
527
|
+
white-space: nowrap;
|
|
528
|
+
}
|
|
529
|
+
.search-panel__history-version time {
|
|
530
|
+
color: var(--search-panel-muted);
|
|
531
|
+
font-size: 0.7rem;
|
|
532
|
+
white-space: nowrap;
|
|
533
|
+
}
|
|
534
|
+
.search-panel__history-details {
|
|
535
|
+
display: flex;
|
|
536
|
+
flex-wrap: wrap;
|
|
537
|
+
align-items: center;
|
|
538
|
+
gap: 0.25rem;
|
|
539
|
+
padding-bottom: 0.25rem;
|
|
540
|
+
color: var(--search-panel-muted);
|
|
541
|
+
font-size: 0.6875rem;
|
|
542
|
+
}
|
|
543
|
+
.search-panel__history-details button {
|
|
544
|
+
height: auto;
|
|
545
|
+
min-height: 1.5rem;
|
|
546
|
+
padding: 0.125rem 0.375rem;
|
|
547
|
+
font-size: inherit;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.search-panel__loading {
|
|
551
|
+
display: grid;
|
|
552
|
+
gap: 0.5rem;
|
|
553
|
+
padding: 0.75rem;
|
|
554
|
+
}
|
|
555
|
+
.search-panel__loading-title {
|
|
556
|
+
height: 0.8rem;
|
|
557
|
+
width: 55%;
|
|
558
|
+
}
|
|
559
|
+
.search-panel__loading-snippet {
|
|
560
|
+
height: 0.65rem;
|
|
561
|
+
width: 85%;
|
|
562
|
+
margin-bottom: 0.6rem;
|
|
563
|
+
}
|