Skip to content
Source
Sign inSign up

@ff-labs__fff-node@0.11.0.patch

424 lines14.4 KB

1diff --git a/dist/fff-api.d.ts b/dist/fff-api.d.ts
2index 0f90eedca20655ccd30b8f28e433b2094341fbdf..c2ef86927d6e3ab0e8584330fa0ac3fdacc06cf5 100644
3--- a/dist/fff-api.d.ts
4+++ b/dist/fff-api.d.ts
5@@ -199,7 +199,7 @@ export type Location = {
6 export interface SearchResult {
7 /** Matched file items */
8 items: FileItem[];
9- /** Corresponding scores for each item */
10+ /** Corresponding scores for each item. Empty when the page has more than 200 items (patched in T3 Code to skip per-item score FFI calls). */
11 scores: Score[];
12 /** Total number of files that matched */
13 totalMatched: number;
14@@ -238,7 +238,7 @@ export interface DirSearchOptions {
15 export interface DirSearchResult {
16 /** Matched directory items */
17 items: DirItem[];
18- /** Corresponding scores for each item */
19+ /** Corresponding scores for each item. Empty when the page has more than 200 items (patched in T3 Code to skip per-item score FFI calls). */
20 scores: Score[];
21 /** Total number of directories that matched */
22 totalMatched: number;
23@@ -262,7 +262,7 @@ export type MixedItem = {
24 export interface MixedSearchResult {
25 /** Matched items (files and directories interleaved by score) */
26 items: MixedItem[];
27- /** Corresponding scores for each item */
28+ /** Corresponding scores for each item. Empty when the page has more than 200 items (patched in T3 Code to skip per-item score FFI calls). */
29 scores: Score[];
30 /** Total number of items (files + dirs) that matched */
31 totalMatched: number;
32diff --git a/dist/finder.d.ts b/dist/finder.d.ts
33index 452102d720cc19b0560cfc9e2f1a320687047c92..3d3211c70a7de4b97792edb32cc9466c8ba89547 100644
34--- a/dist/finder.d.ts
35+++ b/dist/finder.d.ts
36@@ -242,6 +242,10 @@ export declare class FileFinder implements FileFinderApi {
37 * background watcher might have missed.
38 */
39 scanFiles(): Result<void>;
40+ /**
41+ * Trigger a rescan without blocking the JS thread. Patched in T3 Code.
42+ */
43+ scanFilesAsync(): Promise<Result<void>>;
44 /**
45 * Check if a scan is currently in progress.
46 */
47@@ -254,6 +258,10 @@ export declare class FileFinder implements FileFinderApi {
48 * Get the current scan progress.
49 */
50 getScanProgress(): Result<ScanProgress>;
51+ /**
52+ * Read scan progress without blocking the JS thread. Patched in T3 Code.
53+ */
54+ getScanProgressAsync(): Promise<Result<ScanProgress>>;
55 /**
56 * Wait for the initial file scan to complete.
57 * Non-blocking: polls `isScanning` and yields to the event loop between checks.
58diff --git a/dist/index.js b/dist/index.js
59index 7c1d722eabc8d8eb98998eb48c5fe9d70b749d10..138e590bdcb1bc4fd33f7d195b8d588ac7f86cc9 100644
60--- a/dist/index.js
61+++ b/dist/index.js
62@@ -1,7 +1,7 @@
63 // src/binary.ts
64 import { existsSync, readFileSync } from "fs";
65 import { createRequire } from "module";
66-import { dirname, join } from "path";
67+import { dirname, join, sep } from "path";
68 import { fileURLToPath } from "url";
70 // src/platform.ts
71@@ -120,6 +120,16 @@ function getPackageDir() {
72 function binaryExists() {
73 return findBinary() !== null;
74 }
75+function resolveUnpackedAsarPath(binaryPath) {
76+ const pathSegments = binaryPath.split(sep);
77+ const asarIndex = pathSegments.findLastIndex((segment) => segment.endsWith(".asar"));
78+ if (asarIndex === -1) {
79+ return binaryPath;
80+ }
81+ pathSegments[asarIndex] = `${pathSegments[asarIndex]}.unpacked`;
82+ const unpackedPath = pathSegments.join(sep);
83+ return existsSync(unpackedPath) ? unpackedPath : binaryPath;
84+}
85 function resolveFromNpmPackage() {
86 const packageName = getNpmPackageName();
87 try {
88@@ -128,7 +138,7 @@ function resolveFromNpmPackage() {
89 const packageDir = dirname(packageJsonPath);
90 const binaryPath = join(packageDir, getLibFilename());
91 if (existsSync(binaryPath)) {
92- return binaryPath;
93+ return resolveUnpackedAsarPath(binaryPath);
94 }
95 } catch {
96 }
97@@ -262,6 +272,7 @@ function snakeToCamel(obj) {
98 return result;
99 }
100 function readCString(ptr) {
101+ if (typeof ptr === "string") return ptr;
102 if (isNullPointer(ptr)) return null;
103 try {
104 const [str] = restorePointer({
105@@ -303,6 +314,26 @@ function freeResult(resultPtr) {
106 function readResultEnvelope(funcName, paramsType, paramsValue) {
107 loadLibrary();
108 const { rawPtr, struct: structData } = callRaw(funcName, paramsType, paramsValue);
109+ return envelopeFromRaw(rawPtr, structData);
110+}
111+async function readResultEnvelopeOnNativeThread(funcName, handle) {
112+ loadLibrary();
113+ const rawPtr = await load({
114+ library: LIBRARY_KEY,
115+ funcName,
116+ retType: DataType.External,
117+ paramsType: [DataType.External],
118+ paramsValue: [handle],
119+ freeResultMemory: false,
120+ runInNewThread: true
121+ });
122+ const [structData] = restorePointer({
123+ retType: [FFF_RESULT_STRUCT],
124+ paramsValue: wrapPointer([rawPtr])
125+ });
126+ return envelopeFromRaw(rawPtr, structData);
127+}
128+function envelopeFromRaw(rawPtr, structData) {
129 if (structData.success === 0) {
130 const errorStr = readCString(structData.error);
131 freeResult(rawPtr);
132@@ -311,7 +342,9 @@ function readResultEnvelope(funcName, paramsType, paramsValue) {
133 return { rawPtr, struct: structData };
134 }
135 function callVoidResult(funcName, paramsType, paramsValue) {
136- const res = readResultEnvelope(funcName, paramsType, paramsValue);
137+ return voidResultFromEnvelope(readResultEnvelope(funcName, paramsType, paramsValue));
138+}
139+function voidResultFromEnvelope(res) {
140 if ("ok" in res) return res;
141 freeResult(res.rawPtr);
142 return { ok: true, value: void 0 };
143@@ -426,9 +459,9 @@ function ffiDestroy(handle) {
144 });
145 }
146 var FFF_FILE_ITEM_STRUCT = {
147- relative_path: DataType.External,
148- file_name: DataType.External,
149- git_status: DataType.External,
150+ relative_path: DataType.String,
151+ file_name: DataType.String,
152+ git_status: DataType.String,
153 size: DataType.U64,
154 modified: DataType.U64,
155 access_frecency_score: DataType.I64,
156@@ -445,8 +478,9 @@ var FFF_SCORE_STRUCT = {
157 distance_penalty: DataType.I32,
158 current_file_penalty: DataType.I32,
159 combo_match_boost: DataType.I32,
160+ path_alignment_bonus: DataType.I32,
161 exact_match: DataType.U8,
162- match_type: DataType.External
163+ match_type: DataType.String
164 };
165 var FFF_SEARCH_RESULT_STRUCT = {
166 items: DataType.External,
167@@ -462,8 +496,8 @@ var FFF_SEARCH_RESULT_STRUCT = {
168 location_end_col: DataType.I32
169 };
170 var FFF_DIR_ITEM_STRUCT = {
171- relative_path: DataType.External,
172- dir_name: DataType.External,
173+ relative_path: DataType.String,
174+ dir_name: DataType.String,
175 max_access_frecency: DataType.I32
176 };
177 var FFF_DIR_SEARCH_RESULT_STRUCT = {
178@@ -475,9 +509,9 @@ var FFF_DIR_SEARCH_RESULT_STRUCT = {
179 };
180 var FFF_MIXED_ITEM_STRUCT = {
181 item_type: DataType.U8,
182- relative_path: DataType.External,
183- display_name: DataType.External,
184- git_status: DataType.External,
185+ relative_path: DataType.String,
186+ display_name: DataType.String,
187+ git_status: DataType.String,
188 size: DataType.U64,
189 modified: DataType.U64,
190 access_frecency_score: DataType.I64,
191@@ -500,10 +534,10 @@ var FFF_MIXED_SEARCH_RESULT_STRUCT = {
192 location_end_col: DataType.I32
193 };
194 var FFF_GREP_MATCH_STRUCT = {
195- relative_path: DataType.External,
196- file_name: DataType.External,
197- git_status: DataType.External,
198- line_content: DataType.External,
199+ relative_path: DataType.String,
200+ file_name: DataType.String,
201+ git_status: DataType.String,
202+ line_content: DataType.String,
203 match_ranges: DataType.External,
204 context_before: DataType.External,
205 context_after: DataType.External,
206@@ -598,18 +632,13 @@ function readMixedItemFromRaw(raw) {
207 }
208 function callAccessor(funcName, resultPtr, index, structDef) {
209 loadLibrary();
210- const elemPtr = load({
211+ return load({
212 library: LIBRARY_KEY,
213 funcName,
214- retType: DataType.External,
215+ retType: structDef,
216 paramsType: [DataType.External, DataType.U32],
217 paramsValue: [resultPtr, index]
218 });
219- const [raw] = restorePointer({
220- retType: [structDef],
221- paramsValue: wrapPointer([elemPtr])
222- });
223- return raw;
224 }
225 function ptrOffset(base, bytes) {
226 return load({
227@@ -766,6 +795,7 @@ function parseSearchResult(rawPtr) {
228 }
229 const items = [];
230 const scores = [];
231+ const includeScores = count <= 200;
232 for (let i = 0; i < count; i++) {
233 const rawItem = callAccessor(
234 "fff_search_result_get_item",
235@@ -774,13 +804,15 @@ function parseSearchResult(rawPtr) {
236 FFF_FILE_ITEM_STRUCT
237 );
238 items.push(readFileItemFromRaw(rawItem));
239- const rawScore = callAccessor(
240- "fff_search_result_get_score",
241- handlePtr,
242- i,
243- FFF_SCORE_STRUCT
244- );
245- scores.push(readScoreFromRaw(rawScore));
246+ if (includeScores) {
247+ const rawScore = callAccessor(
248+ "fff_search_result_get_score",
249+ handlePtr,
250+ i,
251+ FFF_SCORE_STRUCT
252+ );
253+ scores.push(readScoreFromRaw(rawScore));
254+ }
255 }
256 load({
257 library: LIBRARY_KEY,
258@@ -824,6 +856,7 @@ function parseDirSearchResult(rawPtr) {
259 const count = sr.count;
260 const items = [];
261 const scores = [];
262+ const includeScores = count <= 200;
263 for (let i = 0; i < count; i++) {
264 const rawItem = callAccessor(
265 "fff_dir_search_result_get_item",
266@@ -832,13 +865,15 @@ function parseDirSearchResult(rawPtr) {
267 FFF_DIR_ITEM_STRUCT
268 );
269 items.push(readDirItemFromRaw(rawItem));
270- const rawScore = callAccessor(
271- "fff_dir_search_result_get_score",
272- handlePtr,
273- i,
274- FFF_SCORE_STRUCT
275- );
276- scores.push(readScoreFromRaw(rawScore));
277+ if (includeScores) {
278+ const rawScore = callAccessor(
279+ "fff_dir_search_result_get_score",
280+ handlePtr,
281+ i,
282+ FFF_SCORE_STRUCT
283+ );
284+ scores.push(readScoreFromRaw(rawScore));
285+ }
286 }
287 load({
288 library: LIBRARY_KEY,
289@@ -897,6 +932,7 @@ function parseMixedSearchResult(rawPtr) {
290 }
291 const items = [];
292 const scores = [];
293+ const includeScores = count <= 200;
294 for (let i = 0; i < count; i++) {
295 const rawItem = callAccessor(
296 "fff_mixed_search_result_get_item",
297@@ -905,13 +941,15 @@ function parseMixedSearchResult(rawPtr) {
298 FFF_MIXED_ITEM_STRUCT
299 );
300 items.push(readMixedItemFromRaw(rawItem));
301- const rawScore = callAccessor(
302- "fff_mixed_search_result_get_score",
303- handlePtr,
304- i,
305- FFF_SCORE_STRUCT
306- );
307- scores.push(readScoreFromRaw(rawScore));
308+ if (includeScores) {
309+ const rawScore = callAccessor(
310+ "fff_mixed_search_result_get_score",
311+ handlePtr,
312+ i,
313+ FFF_SCORE_STRUCT
314+ );
315+ scores.push(readScoreFromRaw(rawScore));
316+ }
317 }
318 load({
319 library: LIBRARY_KEY,
320@@ -1188,7 +1226,11 @@ var FFF_SCAN_PROGRESS_STRUCT = {
321 };
322 function ffiGetScanProgress(handle) {
323 loadLibrary();
324- const res = readResultEnvelope("fff_get_scan_progress", [DataType.External], [handle]);
325+ return scanProgressFromEnvelope(
326+ readResultEnvelope("fff_get_scan_progress", [DataType.External], [handle])
327+ );
328+}
329+function scanProgressFromEnvelope(res) {
330 if ("ok" in res) return res;
331 const handlePtr = res.struct.handle;
332 freeResult(res.rawPtr);
333@@ -1429,6 +1471,8 @@ var FileFinder = class _FileFinder {
334 handle;
335 /** Native ids of this instance's active watch subscriptions. */
336 watchers = /* @__PURE__ */ new Set();
337+ /** Patched in T3 Code: in-flight native-thread calls by function name. */
338+ nativeThreadCalls = /* @__PURE__ */ new Map();
339 constructor(handle) {
340 this.handle = handle;
341 }
342@@ -1485,12 +1529,37 @@ var FileFinder = class _FileFinder {
343 destroy() {
344 if (this.handle !== null) {
345 const handle = this.handle;
346- ffiDestroy(handle);
347+ const watchers = this.watchers;
348 this.handle = null;
349- ffiWatchCleanupAfterDestroy(handle, this.watchers);
350- this.watchers.clear();
351+ this.watchers = /* @__PURE__ */ new Set();
352+ const release = () => {
353+ ffiDestroy(handle);
354+ ffiWatchCleanupAfterDestroy(handle, watchers);
355+ };
356+ // Patched in T3 Code: a native-thread call may still be using the handle.
357+ if (this.nativeThreadCalls.size > 0) {
358+ Promise.allSettled(this.nativeThreadCalls.values()).then(release);
359+ } else {
360+ release();
361+ }
362 }
363 }
364+ /**
365+ * Patched in T3 Code: runs a handle-only call on a libuv pool thread so waiting on fff's
366+ * picker lock never blocks the JS thread. Concurrent callers share one call, so one finder
367+ * holds at most one pool thread per function.
368+ */
369+ callOnNativeThread(funcName, fromEnvelope) {
370+ const guard = this.ensureAlive();
371+ if (!guard.ok) return Promise.resolve(guard);
372+ const pending = this.nativeThreadCalls.get(funcName);
373+ if (pending) return pending;
374+ const call = readResultEnvelopeOnNativeThread(funcName, guard.value).then(fromEnvelope, (cause) => err(String(cause))).finally(() => {
375+ this.nativeThreadCalls.delete(funcName);
376+ });
377+ this.nativeThreadCalls.set(funcName, call);
378+ return call;
379+ }
380 /**
381 * Check if this instance has been destroyed.
382 */
383@@ -1757,6 +1826,18 @@ var FileFinder = class _FileFinder {
384 if (!guard.ok) return guard;
385 return ffiScanFiles(guard.value);
386 }
387+ /**
388+ * Trigger a rescan without blocking the JS thread. Patched in T3 Code.
389+ */
390+ scanFilesAsync() {
391+ return this.callOnNativeThread("fff_scan_files", voidResultFromEnvelope);
392+ }
393+ /**
394+ * Read scan progress without blocking the JS thread. Patched in T3 Code.
395+ */
396+ getScanProgressAsync() {
397+ return this.callOnNativeThread("fff_get_scan_progress", scanProgressFromEnvelope);
398+ }
399 /**
400 * Check if a scan is currently in progress.
401 */
402@@ -1838,7 +1919,8 @@ var FileFinder = class _FileFinder {
403 if (!guard.ok) return guard;
404 const deadline = Date.now() + timeoutMs;
405 while (true) {
406- const progress = this.getScanProgress();
407+ // Patched in T3 Code: the progress read takes the picker lock.
408+ const progress = await this.getScanProgressAsync();
409 if (!progress.ok) return progress;
410 if (!progress.value.isScanning && progress.value.isWarmupComplete) {
411 return { ok: true, value: true };
412diff --git a/package.json b/package.json
413index e000a78b3f79826200979ebb3fe297b599bcea67..84325461c2d963cb42cf72267079d36a419c1398 100644
414--- a/package.json
415+++ b/package.json
416@@ -11,7 +11,7 @@
417 ".": {
418 "types": "./dist/index.d.ts",
419 "import": "./dist/index.js",
420- "require": "./dist/index.cjs",
421+ "require": "./dist/index.js",
422 "default": "./dist/index.js"
423 },
424 "./package.json": "./package.json"