@ff-labs/pi-fff 0.9.1 → 0.9.2-nightly.467aff2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +39 -77
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ff-labs/pi-fff",
3
3
  "public": true,
4
- "version": "0.9.1",
4
+ "version": "0.9.2-nightly.467aff2",
5
5
  "description": "pi extension: FFF-powered fuzzy file and content search",
6
6
  "type": "module",
7
7
  "license": "MIT",
package/src/index.ts CHANGED
@@ -1,26 +1,25 @@
1
1
  /**
2
2
  * pi-fff: FFF-powered file search extension for pi
3
3
  *
4
- * Overrides built-in `find` and `grep` tools with FFF and can also replace
5
- * @-mention autocomplete suggestions in the interactive editor.
4
+ * Overrides built-in `find` and `grep` tools with FFF and adds FFF-backed
5
+ * @-mention autocomplete suggestions to the interactive editor.
6
6
  */
7
7
 
8
8
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
- import { CustomEditor } from "@earendil-works/pi-coding-agent";
10
9
  import {
11
- Text,
12
10
  type AutocompleteItem,
13
11
  type AutocompleteProvider,
12
+ Text,
14
13
  } from "@earendil-works/pi-tui";
15
- import { Type } from "@sinclair/typebox";
16
- import { FileFinder } from "@ff-labs/fff-node";
17
14
  import type {
18
15
  GrepCursor,
19
16
  GrepMode,
20
17
  GrepResult,
21
- SearchResult,
22
18
  MixedItem,
19
+ SearchResult,
23
20
  } from "@ff-labs/fff-node";
21
+ import { FileFinder } from "@ff-labs/fff-node";
22
+ import { Type } from "@sinclair/typebox";
24
23
  import { buildQuery } from "./query";
25
24
 
26
25
  // ---------------------------------------------------------------------------
@@ -273,12 +272,6 @@ function createFffMentionProvider(
273
272
  };
274
273
  }
275
274
 
276
- // FffEditor is defined inside fffExtension() so it can capture `getMentionItems`
277
- // via closure rather than via a 4th constructor parameter. This makes the class
278
- // safe to subclass via `new SubClass(tui, theme, keybindings)` -- the pattern
279
- // pi-vim and pi-image-attachments use to compose editors. See:
280
- // https://github.com/badlogic/pi-mono/issues/3935
281
-
282
275
  // ---------------------------------------------------------------------------
283
276
  // Extension
284
277
  // ---------------------------------------------------------------------------
@@ -391,72 +384,44 @@ export default function fffExtension(pi: ExtensionAPI) {
391
384
  });
392
385
  }
393
386
 
394
- // Editor wrapper that injects FFF @-mention autocomplete alongside base provider.
395
- // Defined inside fffExtension() so the class methods capture `getMentionItems`
396
- // via closure. Subclasses constructed as `new Sub(tui, theme, keybindings)` by
397
- // composability wrappers (pi-vim, pi-image-attachments) still get a working
398
- // mention provider because the closure binding is preserved across subclassing.
399
- class FffEditor extends CustomEditor {
400
- private baseProvider: AutocompleteProvider | undefined;
401
-
402
- override setAutocompleteProvider(provider: AutocompleteProvider): void {
403
- this.baseProvider = provider;
404
- // Create composite provider that handles @-mentions and falls back to base
387
+ function registerAutocompleteProvider(ctx: {
388
+ ui: {
389
+ addAutocompleteProvider: (
390
+ factory: (current: AutocompleteProvider) => AutocompleteProvider,
391
+ ) => void;
392
+ };
393
+ }) {
394
+ ctx.ui.addAutocompleteProvider((current) => {
405
395
  const mentionProvider = createFffMentionProvider(getMentionItems);
406
- const compositeProvider: AutocompleteProvider = {
407
- getSuggestions: async (lines, cursorLine, cursorCol, options) => {
408
- // Try @-mention first
409
- const mentionResult = await mentionProvider.getSuggestions(
410
- lines,
411
- cursorLine,
412
- cursorCol,
413
- options,
414
- );
415
- if (mentionResult) return mentionResult;
416
- // Fall back to base provider
417
- return (
418
- this.baseProvider?.getSuggestions(lines, cursorLine, cursorCol, options) ??
419
- null
420
- );
421
- },
422
- applyCompletion: (lines, cursorLine, cursorCol, item, prefix) => {
423
- // Let mention provider handle @ completions, base provider for others
424
- if (prefix?.startsWith("@")) {
425
- return mentionProvider.applyCompletion!(
426
- lines,
427
- cursorLine,
428
- cursorCol,
429
- item,
430
- prefix,
431
- );
396
+
397
+ return {
398
+ async getSuggestions(lines, cursorLine, cursorCol, options) {
399
+ if (shouldEnableMentions()) {
400
+ try {
401
+ const mentionResult = await mentionProvider.getSuggestions(
402
+ lines,
403
+ cursorLine,
404
+ cursorCol,
405
+ options,
406
+ );
407
+ if (mentionResult) return mentionResult;
408
+ } catch {
409
+ // Delegate when FFF lookup is unavailable.
410
+ }
432
411
  }
412
+
413
+ return current.getSuggestions(lines, cursorLine, cursorCol, options);
414
+ },
415
+ applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
416
+ return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
417
+ },
418
+ shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
433
419
  return (
434
- this.baseProvider?.applyCompletion?.(
435
- lines,
436
- cursorLine,
437
- cursorCol,
438
- item,
439
- prefix,
440
- ) ?? { lines, cursorLine, cursorCol }
420
+ current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true
441
421
  );
442
422
  },
443
423
  };
444
- super.setAutocompleteProvider(compositeProvider);
445
- }
446
- }
447
-
448
- function applyEditorMode(ctx: {
449
- ui: {
450
- setEditorComponent: (
451
- factory: ((tui: any, theme: any, keybindings: any) => any) | undefined,
452
- ) => void;
453
- };
454
- }) {
455
- if (!shouldEnableMentions()) return;
456
-
457
- ctx.ui.setEditorComponent(
458
- (tui: any, theme: any, keybindings: any) => new FffEditor(tui, theme, keybindings),
459
- );
424
+ });
460
425
  }
461
426
 
462
427
  // --- Flags / lifecycle ---
@@ -479,7 +444,7 @@ export default function fffExtension(pi: ExtensionAPI) {
479
444
  pi.on("session_start", async (_event, ctx) => {
480
445
  try {
481
446
  activeCwd = ctx.cwd;
482
- if (shouldEnableMentions()) applyEditorMode(ctx);
447
+ registerAutocompleteProvider(ctx);
483
448
  await ensureFinder(activeCwd);
484
449
  } catch (e: unknown) {
485
450
  ctx.ui.notify(
@@ -947,9 +912,6 @@ export default function fffExtension(pi: ExtensionAPI) {
947
912
  const oldMode = getMode();
948
913
  setMode(newMode);
949
914
 
950
- // Apply immediately using the shared function
951
- applyEditorMode(ctx);
952
-
953
915
  const note =
954
916
  (oldMode === "override") !== (newMode === "override")
955
917
  ? " (tool name change requires restart)"