Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/prompt/common/fileTreeParser.ts
13399 views
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
import type * as vscode from 'vscode';
7
import { URI } from '../../../util/vs/base/common/uri';
8
import { ChatResponseFileTreePart } from '../../../vscodeTypes';
9
10
/**
11
* Converts a markdown-style file tree into a ChatResponseFileTreePart.
12
* @param fileStructure Markdown-style file tree
13
* @param generatePreviewURI Factory that converts a filename to a preview URI
14
*/
15
export function convertFileTreeToChatResponseFileTree(
16
fileStructure: string,
17
generatePreviewURI: (filename: string) => URI,
18
): { chatResponseTree: ChatResponseFileTreePart; projectName: string } {
19
const lines = fileStructure.trim().split('\n');
20
const fileTree: vscode.ChatResponseFileTree[] = [];
21
22
let baseUri: URI | undefined;
23
const root: vscode.ChatResponseFileTree = { name: '', children: [] };
24
fileTree[0] = root;
25
26
for (const line of lines) {
27
let depth = calculateDepth(line);
28
const index = line.lastIndexOf('── ');
29
const name = index >= 0 ? line.substring(index + 3) : line;
30
31
const fileNode: vscode.ChatResponseFileTree = { name };
32
33
if (depth === 0) {
34
baseUri = generatePreviewURI(name);
35
root.name = name;
36
continue;
37
}
38
else {
39
while (depth > 0 && fileTree[depth - 1] === undefined) {
40
depth--;
41
}
42
if (fileTree[depth - 1].children === undefined) {
43
fileTree[depth - 1].children = [fileNode];
44
} else {
45
fileTree[depth - 1].children?.push(fileNode);
46
}
47
fileTree[depth] = fileNode;
48
}
49
}
50
if (baseUri === undefined) {
51
throw new Error('Base URI is undefined');
52
}
53
const filteredTree = filterChatResponseFileTree(root.children!);
54
root.children = filteredTree.sort((a, b) => (a.children && !b.children) ? -1 : 1);
55
return {
56
chatResponseTree: new ChatResponseFileTreePart([root], baseUri),
57
projectName: root.name
58
};
59
}
60
61
/**
62
* List filenames in the tree, separated by forward-slashes.
63
*/
64
export function listFilesInResponseFileTree(tree: vscode.ChatResponseFileTree[]): string[] {
65
const queue = tree.map(node => ({ node, path: node.name }));
66
const result: string[] = [];
67
68
while (queue.length > 0) {
69
const { node, path } = queue.shift()!;
70
if (node.children && node.children.length > 0) {
71
for (const child of node.children) {
72
queue.push({ node: child, path: `${path}/${child.name}` });
73
}
74
} else {
75
result.push(path);
76
}
77
}
78
79
return result;
80
}
81
82
function calculateDepth(inputString: string): number {
83
let depth = (inputString.match(/│ /g) || []).length;
84
depth += (inputString.match(/\| /g) || []).length;
85
depth += (inputString.match(/ /g) || []).length;
86
depth += (inputString.match(/├── /g) || []).length;
87
depth += (inputString.match(/└── /g) || []).length;
88
89
return depth;
90
}
91
92
const filterList = [
93
/* compile/runtime files */ 'node_modules', 'out', 'bin', 'debug', 'obj', 'lib', '.dll', '.pdb', '.lib',
94
/* image assets */ '.jpg', '.png', '.ico', '.gif', '.svg', '.jpeg', '.tiff', '.bmp', '.webp', '.jpeg',
95
/* other files we should not be included in a new project */'.gitignore', 'LICENSE.txt', 'yarn.lock', 'package-lock.json'
96
];
97
98
function filterChatResponseFileTree(fileTree: vscode.ChatResponseFileTree[]): vscode.ChatResponseFileTree[] {
99
const filteredTree: vscode.ChatResponseFileTree[] = [];
100
101
for (const node of fileTree) {
102
103
if (!isNodeInFilterList(node)) {
104
if (node.children) {
105
node.children = filterChatResponseFileTree(node.children);
106
}
107
filteredTree.push(node);
108
}
109
}
110
111
return filteredTree;
112
}
113
114
function isNodeInFilterList(node: vscode.ChatResponseFileTree): boolean {
115
if (filterList.includes(node.name)) {
116
return true;
117
}
118
119
return false;
120
}
121
122