-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextension.ts
More file actions
199 lines (170 loc) · 6.58 KB
/
extension.ts
File metadata and controls
199 lines (170 loc) · 6.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
export function activate(context: vscode.ExtensionContext) {
console.log('CopyContext extension is now active');
// This command will be used from the explorer context menu
const copyFromExplorerCommand = vscode.commands.registerCommand(
'copycontext.copyFromExplorer',
async (fileUri: vscode.Uri, selectedFiles: vscode.Uri[]) => {
try {
console.log('copyFromExplorer called with:', fileUri);
console.log('Additional argument:', selectedFiles);
// If we have selectedFiles, use them
if (selectedFiles && Array.isArray(selectedFiles) && selectedFiles.length > 0) {
await processAndCopyFiles(selectedFiles);
return;
}
// If we have a single fileUri with an array property (some VS Code versions do this)
if (fileUri && Array.isArray(fileUri)) {
await processAndCopyFiles(fileUri);
return;
}
// For a single file
if (fileUri && fileUri.fsPath) {
await processAndCopyFiles([fileUri]);
return;
}
vscode.window.showErrorMessage('No files were selected to copy.');
} catch (error) {
console.error('Error in copyFromExplorer:', error);
vscode.window.showErrorMessage(`Error copying files: ${error}`);
}
}
);
// This command will be used from the editor context menu and keybinding
const copyFromEditorCommand = vscode.commands.registerCommand(
'copycontext.copyFromEditor',
async () => {
try {
const editor = vscode.window.activeTextEditor;
if (editor) {
const filePath = editor.document.uri.fsPath;
const fileContent = editor.document.getText(
editor.selection.isEmpty ? undefined : editor.selection
);
const relativePath = getRelativePath(filePath);
const fileInfo = [{ path: relativePath, content: fileContent }];
const formattedText = formatFilesForLLM(fileInfo);
await copyToClipboard(formattedText);
vscode.window.showInformationMessage('File copied with context!');
} else {
vscode.window.showErrorMessage('No active editor found.');
}
} catch (error) {
console.error('Error in copyFromEditor:', error);
vscode.window.showErrorMessage(`Error copying from editor: ${error}`);
}
}
);
// This is the main command that will be invoked from the command palette
const copyWithContextCommand = vscode.commands.registerCommand(
'copycontext.copyWithContext',
async () => {
try {
// Check if we're in the editor
if (vscode.window.activeTextEditor) {
await vscode.commands.executeCommand('copycontext.copyFromEditor');
return;
}
// If we reached here, we're not in the editor, so we need to get the selected files
// Since we can't get them directly, prompt the user for confirmation
const result = await vscode.window.showInformationMessage(
'Please use the context menu in the Explorer view to copy multiple files.',
'Show Instructions'
);
if (result === 'Show Instructions') {
vscode.window.showInformationMessage(
'To copy multiple files: 1) Select files in Explorer 2) Right-click 3) Select "Copy With Context"',
{ modal: true }
);
}
} catch (error) {
console.error('Error in copyWithContext:', error);
vscode.window.showErrorMessage(`Error: ${error}`);
}
}
);
// Helper function to process and copy multiple files
async function processAndCopyFiles(uris: vscode.Uri[]): Promise<void> {
try {
if (uris.length > 1) {
vscode.window.showInformationMessage(`Processing ${uris.length} files...`);
}
let fileInfo: { path: string; content: string }[] = [];
for (const uri of uris) {
const filePath = uri.fsPath;
const fileContent = await readFileContent(filePath);
const relativePath = getRelativePath(filePath);
fileInfo.push({ path: relativePath, content: fileContent });
}
if (fileInfo.length > 0) {
const formattedText = formatFilesForLLM(fileInfo);
await copyToClipboard(formattedText);
const message = fileInfo.length === 1
? 'File copied with context!'
: `${fileInfo.length} files copied with context!`;
vscode.window.showInformationMessage(message);
} else {
vscode.window.showErrorMessage('No files were processed.');
}
} catch (error) {
console.error('Error processing files:', error);
throw error;
}
}
context.subscriptions.push(
copyWithContextCommand,
copyFromExplorerCommand,
copyFromEditorCommand
);
}
// Helper function to read file content
async function readFileContent(filePath: string): Promise<string> {
try {
const stats = fs.statSync(filePath);
// If it's a directory, return a directory indicator
if (stats.isDirectory()) {
return '[Directory]';
}
// Check if file is binary or too large
if (stats.size > 1024 * 1024) { // Limit to 1MB
return '[File too large to include content]';
}
return fs.readFileSync(filePath, 'utf8');
} catch (error) {
console.error(`Error reading file ${filePath}:`, error);
return `[Error reading file: ${error}]`;
}
}
// Helper function to get relative path from workspace
function getRelativePath(filePath: string): string {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (workspaceFolders && workspaceFolders.length > 0) {
// Try to get the path relative to the workspace
for (const folder of workspaceFolders) {
const relativePath = path.relative(folder.uri.fsPath, filePath);
if (!relativePath.startsWith('..')) {
return relativePath;
}
}
}
// If no workspace or file is outside workspace, return the filename
return path.basename(filePath);
}
// Format the files in a way that's useful for LLMs
function formatFilesForLLM(files: { path: string; content: string }[]): string {
let result = '';
for (const file of files) {
result += `File: ${file.path}\n`;
result += '```\n';
result += file.content;
result += '\n```\n\n';
}
return result;
}
// Helper function to copy to clipboard
async function copyToClipboard(text: string): Promise<void> {
return vscode.env.clipboard.writeText(text);
}
export function deactivate() {}