Skip to content

Commit ff250e9

Browse files
Merge branch 'merogge/folder' into Main
Signed-off-by: Christopher Birnie-Browne <153604499+Git-Hub-Chris@users.noreply.github.com>
2 parents 0a6590d + e00ff28 commit ff250e9

File tree

16 files changed

+845
-46
lines changed

16 files changed

+845
-46
lines changed

extensions/terminal-suggest/src/completions/index.d.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,5 +1296,50 @@ declare namespace Fig {
12961296
*
12971297
*/
12981298
cache?: Cache;
1299+
1300+
/**
1301+
* Options related to file paths used in the generator, including filtering options and handling of file extensions.
1302+
*/
1303+
filepathOptions?: FilepathsOptions; // <-- VS Code edit to return file resource request config as we resolve files in core
1304+
}
1305+
1306+
type FilepathsOptions = {
1307+
/**
1308+
* Show suggestions with any of these extensions. Do not include the leading dot.
1309+
*/
1310+
extensions?: string[];
1311+
/**
1312+
* Show suggestions where the name exactly matches one of these strings
1313+
*/
1314+
equals?: string | string[];
1315+
/**
1316+
* Show suggestions where the name matches this expression
1317+
*/
1318+
matches?: RegExp;
1319+
/**
1320+
* Will treat folders like files, filtering based on the name.
1321+
*/
1322+
filterFolders?: boolean;
1323+
/**
1324+
* Set properties of suggestions of type 'file'.
1325+
*/
1326+
editFileSuggestions?: Omit<Fig.Suggestion, 'name' | 'type'>;
1327+
/**
1328+
* Set properties of suggestions of type 'folder'.
1329+
*/
1330+
editFolderSuggestions?: Omit<Fig.Suggestion, 'name' | 'type'>;
1331+
/**
1332+
* Start to suggest filepaths and folders from this directory.
1333+
*/
1334+
rootDirectory?: string;
1335+
/**
1336+
* Set how the generator should display folders:
1337+
* - **Default:** `always` will always suggest folders.
1338+
* - `never`: will never suggest folders.
1339+
* - `only`: will show only folders and no files.
1340+
*/
1341+
showFolders?: 'always' | 'never' | 'only';
12991342
}
13001343
}
1344+
1345+

extensions/terminal-suggest/src/completions/upstream/apt.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { filepaths } from '../../helpers/filepaths';
1+
import { filepaths } from '../../fig/autocomplete-tools/generators'
22

33
const packages: Fig.Generator = {
44
// only trigger when the token length transitions to or from 0
@@ -134,7 +134,11 @@ const completionSpec: Fig.Spec = {
134134
name: "package",
135135
description: "The package you want to install",
136136
isVariadic: true,
137-
generators: [packages, filepaths({ extensions: ["deb"] })],
137+
template: 'filepaths',
138+
generators: [
139+
packages,
140+
filepaths({ extensions: ["deb"] })
141+
],
138142
},
139143
options: [
140144
...installationOptions,

extensions/terminal-suggest/src/completions/upstream/node.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { filepaths } from '../../helpers/filepaths';
1+
import { filepaths } from '../../fig/autocomplete-tools/generators'
22

33
const completionSpec: Fig.Subcommand = {
44
name: "node",
55
description: "Run the node interpreter",
66
args: {
77
name: "node script",
88
isScript: true,
9+
template: 'filepaths',
910
generators: filepaths({
1011
extensions: ["mjs", "js", "cjs"],
1112
editFileSuggestions: { priority: 76 },

extensions/terminal-suggest/src/completions/upstream/python.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { filepaths } from '../../helpers/filepaths';
1+
import { filepaths } from '../../fig/autocomplete-tools/generators'
22

33
const completionSpec: Fig.Spec = {
44
name: "python",
@@ -21,7 +21,7 @@ const completionSpec: Fig.Spec = {
2121
},
2222
args: {
2323
name: "python script",
24-
isScript: true,
24+
template: "filepaths",
2525
generators: filepaths({
2626
extensions: ["py"],
2727
editFileSuggestions: { priority: 76 },

extensions/terminal-suggest/src/fig/autocomplete-parser/parseArguments.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export type ArgumentParserState = {
9090
// Used to exclude subcommand suggestions after user has entered a subcommand arg.
9191
haveEnteredSubcommandArgs: boolean;
9292
isEndOfOptions: boolean;
93+
fileExtensions?: string[];
9394
};
9495

9596
// Result with derived completionObj/currentArg from cached state.
@@ -101,6 +102,7 @@ export type ArgumentParserResult = {
101102
commandIndex: number;
102103
suggestionFlags: SuggestionFlags;
103104
annotations: Annotation[];
105+
fileExtensions?: string[];
104106
};
105107

106108
export const createArgState = (args?: Internal.Arg[]): ArgArrayState => {
@@ -757,6 +759,7 @@ export const getResultFromState = (
757759
currentArg,
758760
searchTerm,
759761
suggestionFlags,
762+
fileExtensions: state.fileExtensions,
760763
};
761764
};
762765

@@ -1045,7 +1048,15 @@ const parseArgumentsCached = async (
10451048
// } else {
10461049
// parseArgumentsCache.set(cacheKey, state);
10471050
// }
1048-
1051+
if ('args' in spec) {
1052+
for (const arg of Array.isArray(spec.args) ? spec.args : [spec.args]) {
1053+
for (const generator of Array.isArray(arg?.generators) ? arg.generators : [arg?.generators]) {
1054+
if (generator?.filepathOptions?.extensions) {
1055+
state.fileExtensions = generator.filepathOptions.extensions;
1056+
}
1057+
}
1058+
}
1059+
}
10491060
return state;
10501061
};
10511062

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
export { filepaths, FilepathsOptions, folders } from './src/filepaths';
7+
export * from './src/keyvalue';
8+
export { ai } from './src/ai';
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
export type GeneratorFn<T> = (args: {
6+
tokens: string[];
7+
executeCommand: Fig.ExecuteCommandFunction;
8+
generatorContext: Fig.GeneratorContext;
9+
}) => Promise<T> | T;
10+
11+
const MAX_TOKENS = 4097;
12+
const TOKEN_TO_CHAR_RATIO = 4;
13+
const MARGIN_RATIO = 0.8;
14+
const MAX_CHARS = MAX_TOKENS * TOKEN_TO_CHAR_RATIO * MARGIN_RATIO;
15+
16+
/**
17+
* A generator that uses the Fig AI API to generate suggestions.
18+
*
19+
* @param prompt The prompt to use for the AI. Can be a string or a generator function.
20+
* @param message The message to send to the AI. Can be a string or a generator function.
21+
* @param postProcess A function to post-process the AI's response.
22+
* @param temperature The temperature to use for the AI.
23+
* @returns A Fig generator.
24+
*/
25+
export function ai({
26+
name,
27+
prompt,
28+
message,
29+
postProcess,
30+
temperature,
31+
splitOn,
32+
}: {
33+
name: string;
34+
prompt?: string | GeneratorFn<string>;
35+
message: string | GeneratorFn<string | null> | null;
36+
postProcess?: (out: string) => Fig.Suggestion[];
37+
temperature?: number;
38+
splitOn?: string;
39+
}): Fig.Generator {
40+
return {
41+
scriptTimeout: 15000,
42+
custom: async (tokens, executeCommand, generatorContext) => {
43+
const settingOutput = await executeCommand({
44+
command: 'fig',
45+
args: ['settings', '--format', 'json', 'autocomplete.ai.enabled'],
46+
});
47+
48+
if (!JSON.parse(settingOutput.stdout)) {
49+
return [];
50+
}
51+
52+
const promptString =
53+
typeof prompt === 'function'
54+
? await prompt({
55+
tokens,
56+
executeCommand,
57+
generatorContext,
58+
})
59+
: prompt;
60+
61+
const messageString =
62+
typeof message === 'function'
63+
? await message({
64+
tokens,
65+
executeCommand,
66+
generatorContext,
67+
})
68+
: message;
69+
70+
if (messageString === null || messageString.length === 0) {
71+
console.warn('No message provided to AI generator');
72+
return [];
73+
}
74+
75+
const budget = MAX_CHARS - (promptString?.length ?? 0);
76+
77+
const body = {
78+
model: 'gpt-3.5-turbo',
79+
source: 'autocomplete',
80+
name,
81+
messages: [
82+
...(promptString
83+
? [
84+
{
85+
role: 'system',
86+
content: promptString,
87+
},
88+
]
89+
: []),
90+
{
91+
role: 'user',
92+
content: messageString.slice(0, budget),
93+
},
94+
],
95+
temperature,
96+
};
97+
98+
const bodyJson = JSON.stringify(body);
99+
100+
const requestOutput = await executeCommand({
101+
command: 'fig',
102+
args: ['_', 'request', '--route', '/ai/chat', '--method', 'POST', '--body', bodyJson],
103+
});
104+
const json = JSON.parse(requestOutput.stdout);
105+
106+
const a =
107+
json?.choices
108+
.map((c: any) => c?.message?.content)
109+
.filter((c: unknown) => typeof c === 'string')
110+
.flatMap((c: string) =>
111+
splitOn ? c.split(splitOn).filter((s) => s.trim().length > 0) : [c]
112+
)
113+
.map((out: string) => {
114+
if (postProcess) {
115+
return postProcess(out);
116+
}
117+
const text = out.trim().replace(/\n/g, ' ');
118+
// eslint-disable-next-line local/code-no-dangerous-type-assertions allow-any-unicode-next-line
119+
return {
120+
icon: '🪄',
121+
name: text,
122+
insertValue: `'${text}'`,
123+
description: 'Generated by Fig AI',
124+
} as Fig.Suggestion;
125+
}) ?? [];
126+
127+
return a;
128+
},
129+
};
130+
}

0 commit comments

Comments
 (0)