follow xml pattern

This commit is contained in:
2025-03-11 18:40:20 +00:00
parent 3676136692
commit 0ec4e8e2d2
4 changed files with 150 additions and 68 deletions

View File

@@ -45,19 +45,19 @@ export function activate(context: vscode.ExtensionContext) {
state === vscode.TreeItemCheckboxState.Checked state === vscode.TreeItemCheckboxState.Checked
); );
// Update XML edits button text if that setting changed // Update formatting instructions button text if that setting changed
if (item.settingKey === 'xmlEditsEnabled') { if (item.settingKey === 'includeFormattingInstructions') {
xmlEditsButton.text = prompterTreeProvider.isXmlEditsEnabled() ? xmlEditsButton.text = prompterTreeProvider.isXmlEditsEnabled() ?
"$(check) XML Edits" : "$(diff-added) XML Edits"; "$(check) Formatting Instructions" : "$(diff-added) Formatting Instructions";
} }
} }
} }
}); });
// Create XML edits toggle button // Create formatting instructions toggle button
const xmlEditsButton = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); const xmlEditsButton = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
xmlEditsButton.text = "$(diff-added) XML Edits"; xmlEditsButton.text = "$(diff-added) Formatting Instructions";
xmlEditsButton.tooltip = "Toggle XML Edits mode"; xmlEditsButton.tooltip = "Toggle formatting instructions mode";
xmlEditsButton.command = 'prompter.toggleXmlEdits'; xmlEditsButton.command = 'prompter.toggleXmlEdits';
xmlEditsButton.show(); xmlEditsButton.show();

View File

@@ -1,15 +1,13 @@
// Settings interface for the Prompter extension // Settings interface for the Prompter extension
export interface PrompterSettings { export interface PrompterSettings {
xmlEditsEnabled: boolean; includeFormattingInstructions: boolean;
includeLineNumbers: boolean;
includeComments: boolean;
tokenCalculationEnabled: boolean; tokenCalculationEnabled: boolean;
includeFileMap: boolean;
} }
// Default settings values // Default settings values
export const DEFAULT_SETTINGS: PrompterSettings = { export const DEFAULT_SETTINGS: PrompterSettings = {
xmlEditsEnabled: false, includeFormattingInstructions: false,
includeLineNumbers: false, tokenCalculationEnabled: true,
includeComments: true, includeFileMap: true
tokenCalculationEnabled: true
}; };

View File

@@ -129,10 +129,9 @@ export class PrompterTreeProvider implements vscode.TreeDataProvider<FileTreeIte
// Get settings items for the tree view // Get settings items for the tree view
private getSettingsItems(): SettingTreeItem[] { private getSettingsItems(): SettingTreeItem[] {
return [ return [
new SettingTreeItem('XML Edits', 'xmlEditsEnabled', this.settings.xmlEditsEnabled), new SettingTreeItem('Include Formatting Instructions', 'includeFormattingInstructions', this.settings.includeFormattingInstructions),
new SettingTreeItem('Include Line Numbers', 'includeLineNumbers', this.settings.includeLineNumbers), new SettingTreeItem('Token Calculation', 'tokenCalculationEnabled', this.settings.tokenCalculationEnabled),
new SettingTreeItem('Include Comments', 'includeComments', this.settings.includeComments), new SettingTreeItem('Include File Map', 'includeFileMap', this.settings.includeFileMap)
new SettingTreeItem('Token Calculation', 'tokenCalculationEnabled', this.settings.tokenCalculationEnabled)
]; ];
} }
@@ -147,15 +146,15 @@ export class PrompterTreeProvider implements vscode.TreeDataProvider<FileTreeIte
return this.showingSettings; return this.showingSettings;
} }
// Toggle XML edits setting // Toggle formatting instructions setting
toggleXmlEdits(): void { toggleXmlEdits(): void {
this.settings.xmlEditsEnabled = !this.settings.xmlEditsEnabled; this.settings.includeFormattingInstructions = !this.settings.includeFormattingInstructions;
this.refresh(); this.refresh();
} }
// Check if XML edits are enabled // Check if formatting instructions are enabled
isXmlEditsEnabled(): boolean { isXmlEditsEnabled(): boolean {
return this.settings.xmlEditsEnabled; return this.settings.includeFormattingInstructions;
} }
// Get all settings // Get all settings

View File

@@ -31,12 +31,8 @@ export class PromptGenerator {
fileContents.set(filePath, { content, tokens }); fileContents.set(filePath, { content, tokens });
} }
// Generate the prompt based on settings // Always generate XML prompt
if (settings.xmlEditsEnabled) {
return this.generateXMLPrompt(fileContents, settings); return this.generateXMLPrompt(fileContents, settings);
} else {
return this.generatePlainPrompt(fileContents, settings);
}
} }
/** /**
@@ -55,16 +51,7 @@ export class PromptGenerator {
// Add the file to the prompt // Add the file to the prompt
promptText += `File: ${fileName}\n`; promptText += `File: ${fileName}\n`;
// Add line numbers if enabled
if (settings.includeLineNumbers) {
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
promptText += `${i + 1}: ${lines[i]}\n`;
}
} else {
promptText += `${content}\n`; promptText += `${content}\n`;
}
promptText += '\n'; promptText += '\n';
} }
@@ -78,58 +65,156 @@ export class PromptGenerator {
} }
/** /**
* Generate an XML formatted prompt * Generate an XML formatted prompt following the new schema format
* @param files Map of file paths to content and token counts * @param files Map of file paths to content and token counts
* @param settings Settings to apply * @param settings Settings to apply
* @returns XML formatted prompt * @returns XML formatted prompt
*/ */
private static generateXMLPrompt(files: Map<string, { content: string; tokens: number }>, settings: PrompterSettings): string { private static generateXMLPrompt(files: Map<string, { content: string; tokens: number }>, settings: PrompterSettings): string {
const xmlParts = ['<?xml version="1.0" encoding="UTF-8"?>', '<prompt>']; const xmlParts: string[] = [];
// Add files section // Include XML formatting instructions if enabled
xmlParts.push(' <files>'); if (settings.includeFormattingInstructions) {
try {
// Get the workspace root path
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
const formattingInstructionsPath = path.join(workspaceRoot, '..', 'project_management', 'xml_formatting_instructions.xml');
if (fs.existsSync(formattingInstructionsPath)) {
const instructions = fs.readFileSync(formattingInstructionsPath, 'utf8');
xmlParts.push(instructions);
}
} catch (error) {
console.error('Error reading XML formatting instructions:', error);
}
}
// Generate file map section if enabled in settings
if (settings.includeFileMap) {
xmlParts.push('<file_map>');
// Get the workspace root path
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
xmlParts.push(workspaceRoot);
// Create a tree representation of the files
const fileTree = this.generateFileTree(files, workspaceRoot);
xmlParts.push(fileTree);
xmlParts.push('</file_map>');
}
// Generate file contents section
xmlParts.push('<file_contents>');
// Add each file with its content
for (const [filePath, { content, tokens }] of files) { for (const [filePath, { content, tokens }] of files) {
const extension = path.extname(filePath); const extension = path.extname(filePath);
let language = extension.substring(1); // Remove the dot let language = extension.substring(1); // Remove the dot
// Handle special cases // Handle special cases for language detection
if (extension === '.js' || extension === '.jsx') { if (extension === '.js' || extension === '.jsx') {
language = 'javascript'; language = 'javascript';
} else if (extension === '.ts' || extension === '.tsx') { } else if (extension === '.ts' || extension === '.tsx') {
language = 'typescript'; language = 'typescript';
} else if (extension === '.md') {
language = 'md';
} else if (extension === '.py') {
language = 'python';
} else if (extension === '.html') {
language = 'html';
} else if (extension === '.css') {
language = 'css';
} else if (extension === '.json') {
language = 'json';
} }
xmlParts.push(' <file>'); // Use content as is
xmlParts.push(` <path>${path.basename(filePath)}</path>`); const formattedContent = content;
xmlParts.push(` <type>${language}</type>`);
xmlParts.push(` <tokens>${tokens}</tokens>`);
// Format content based on settings // Get the workspace root path if not already defined
let formattedContent = content; const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
if (settings.includeLineNumbers) {
const lines = content.split('\n'); // Add file entry
formattedContent = lines.map((line, i) => `${i + 1}: ${line}`).join('\n'); xmlParts.push(`File: ${this.getRelativePath(filePath, workspaceRoot)}`);
xmlParts.push(`\`\`\`${language}`);
xmlParts.push(formattedContent);
xmlParts.push('\`\`\`');
} }
xmlParts.push(` <content><![CDATA[${formattedContent}]]></content>`); xmlParts.push('</file_contents>');
xmlParts.push(' </file>');
}
xmlParts.push(' </files>');
// Add options based on settings // Calculate tokens for toast notification but don't include in XML
xmlParts.push(' <options>');
if (settings.includeLineNumbers) {
xmlParts.push(' <include_line_numbers>true</include_line_numbers>');
}
if (!settings.includeComments) {
xmlParts.push(' <exclude_comments>true</exclude_comments>');
}
if (settings.tokenCalculationEnabled) { if (settings.tokenCalculationEnabled) {
xmlParts.push(` <total_tokens>${Array.from(files.values()).reduce((sum, { tokens }) => sum + tokens, 0)}</total_tokens>`); const totalTokens = Array.from(files.values()).reduce((sum, { tokens }) => sum + tokens, 0);
// We'll show this in a toast notification but not include it in the XML
vscode.window.showInformationMessage(`Total tokens: ${totalTokens}`);
} }
xmlParts.push(' </options>');
xmlParts.push('</prompt>');
return xmlParts.join('\n'); return xmlParts.join('\n');
} }
/**
* Generate a tree representation of files
* @param files Map of file paths
* @param rootPath The workspace root path
* @returns String representation of the file tree
*/
private static generateFileTree(files: Map<string, any>, rootPath: string): string {
// Create a simple tree representation
const treeLines: string[] = [];
// Group files by directory
const dirMap = new Map<string, string[]>();
for (const filePath of files.keys()) {
const relativePath = this.getRelativePath(filePath, rootPath);
const dir = path.dirname(relativePath);
if (!dirMap.has(dir)) {
dirMap.set(dir, []);
}
dirMap.get(dir)?.push(path.basename(filePath));
}
// Sort directories
const sortedDirs = Array.from(dirMap.keys()).sort();
// Build the tree
for (let i = 0; i < sortedDirs.length; i++) {
const dir = sortedDirs[i];
const isLast = i === sortedDirs.length - 1;
const prefix = isLast ? '└── ' : '├── ';
// Skip root directory
if (dir !== '.') {
treeLines.push(`${prefix}${dir}`);
}
// Add files
const files = dirMap.get(dir)?.sort() || [];
for (let j = 0; j < files.length; j++) {
const file = files[j];
const isLastFile = j === files.length - 1;
const filePrefix = dir === '.' ? (isLastFile ? '└── ' : '├── ') : ' ' + (isLastFile ? '└── ' : '├── ');
treeLines.push(`${filePrefix}${file}`);
}
}
return treeLines.join('\n');
}
/**
* Get the path relative to the workspace root
* @param filePath Absolute file path
* @param rootPath Workspace root path
* @returns Relative path
*/
private static getRelativePath(filePath: string, rootPath: string): string {
if (filePath.startsWith(rootPath)) {
const relativePath = filePath.substring(rootPath.length);
return relativePath.startsWith('/') ? relativePath.substring(1) : relativePath;
}
return filePath;
}
} }