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
);
// Update XML edits button text if that setting changed
if (item.settingKey === 'xmlEditsEnabled') {
// Update formatting instructions button text if that setting changed
if (item.settingKey === 'includeFormattingInstructions') {
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);
xmlEditsButton.text = "$(diff-added) XML Edits";
xmlEditsButton.tooltip = "Toggle XML Edits mode";
xmlEditsButton.text = "$(diff-added) Formatting Instructions";
xmlEditsButton.tooltip = "Toggle formatting instructions mode";
xmlEditsButton.command = 'prompter.toggleXmlEdits';
xmlEditsButton.show();

View File

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

View File

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

View File

@@ -31,12 +31,8 @@ export class PromptGenerator {
fileContents.set(filePath, { content, tokens });
}
// Generate the prompt based on settings
if (settings.xmlEditsEnabled) {
return this.generateXMLPrompt(fileContents, settings);
} else {
return this.generatePlainPrompt(fileContents, settings);
}
// Always generate XML prompt
return this.generateXMLPrompt(fileContents, settings);
}
/**
@@ -55,16 +51,7 @@ export class PromptGenerator {
// Add the file to the prompt
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';
}
@@ -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 settings Settings to apply
* @returns XML formatted prompt
*/
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
xmlParts.push(' <files>');
// Include XML formatting instructions if enabled
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) {
const extension = path.extname(filePath);
let language = extension.substring(1); // Remove the dot
// Handle special cases
// Handle special cases for language detection
if (extension === '.js' || extension === '.jsx') {
language = 'javascript';
} else if (extension === '.ts' || extension === '.tsx') {
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>');
xmlParts.push(` <path>${path.basename(filePath)}</path>`);
xmlParts.push(` <type>${language}</type>`);
xmlParts.push(` <tokens>${tokens}</tokens>`);
// Use content as is
const formattedContent = content;
// Format content based on settings
let formattedContent = content;
if (settings.includeLineNumbers) {
const lines = content.split('\n');
formattedContent = lines.map((line, i) => `${i + 1}: ${line}`).join('\n');
}
// Get the workspace root path if not already defined
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri?.fsPath || '';
xmlParts.push(` <content><![CDATA[${formattedContent}]]></content>`);
xmlParts.push(' </file>');
// Add file entry
xmlParts.push(`File: ${this.getRelativePath(filePath, workspaceRoot)}`);
xmlParts.push(`\`\`\`${language}`);
xmlParts.push(formattedContent);
xmlParts.push('\`\`\`');
}
xmlParts.push(' </files>');
// Add options based on settings
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>');
}
xmlParts.push('</file_contents>');
// Calculate tokens for toast notification but don't include in XML
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');
}
/**
* 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;
}
}