Skip to content

Commit

Permalink
Fix issue with XML/HTML output
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas-McKanna-Test committed Dec 16, 2024
1 parent 4b7786c commit 0b85226
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 104 deletions.
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "Files2Prompt",
"icon": "./files2prompt-icon.webp",
"description": "Copy file contents for LLM prompts",
"version": "1.7.1",
"version": "1.7.2",
"publisher": "thomas-mckanna",
"keywords": [
"files",
Expand Down Expand Up @@ -192,4 +192,4 @@
"fast-xml-parser": "^4.5.0",
"ignore": "^6.0.2"
}
}
}
138 changes: 41 additions & 97 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export function activate(context: vscode.ExtensionContext) {
manageCheckboxStateManually: true,
});

// Add fileTreeProvider to ensure proper disposal
context.subscriptions.push(fileTreeProvider);

let history: string[][] = [];
Expand All @@ -34,41 +33,32 @@ export function activate(context: vscode.ExtensionContext) {
return;
}

// Before saving the current selection to history, check if it's the same as the last selection
const lastSelection = history[historyPosition] || [];
if (!arraysEqual(checkedFiles, lastSelection)) {
// Save the current selection to the history
if (historyPosition < history.length - 1) {
history = history.slice(0, historyPosition + 1);
}
history.push([...checkedFiles]); // Save a copy of the current selection
history.push([...checkedFiles]);
historyPosition++;
}

const xmlOutput = await generateXmlOutput(checkedFiles);

// Include system message if provided
const config = vscode.workspace.getConfiguration("files2prompt");
const systemMessage = config.get<string>("systemMessage");

let finalOutput = xmlOutput;

if (systemMessage && systemMessage.trim() !== "") {
// Escape any ']]>' sequences in systemMessage
const safeSystemMessage = systemMessage.replace(
/]]>/g,
"]]]]><![CDATA[>"
);
finalOutput =
`<systemMessage>
<![CDATA[
${safeSystemMessage}
>
${systemMessage}
]]>
</systemMessage>
` + finalOutput;
}

// Copy to clipboard
await vscode.env.clipboard.writeText(finalOutput);

vscode.window.showInformationMessage(
Expand All @@ -83,11 +73,8 @@ ${safeSystemMessage}
if (historyPosition > 0) {
historyPosition--;
const previousSelection = history[historyPosition];

// Update the file selections in the FileTreeProvider
await fileTreeProvider.setCheckedFiles(previousSelection);
} else {
// Show warning message
vscode.window.showWarningMessage(
"No previous selection to go back to."
);
Expand All @@ -97,11 +84,8 @@ ${safeSystemMessage}
if (historyPosition < history.length - 1) {
historyPosition++;
const nextSelection = history[historyPosition];

// Update the file selections in the FileTreeProvider
await fileTreeProvider.setCheckedFiles(nextSelection);
} else {
// Show warning message
vscode.window.showWarningMessage(
"No next selection to go forward to."
);
Expand All @@ -111,69 +95,57 @@ ${safeSystemMessage}
const clipboardContent = await vscode.env.clipboard.readText();
await processXmlContent(clipboardContent);
}),
vscode.commands.registerCommand(
"files2prompt.copyOpenFiles",
async () => {
const tabGroups: ReadonlyArray<vscode.TabGroup> =
vscode.window.tabGroups.all;

let xmlContent = "";

for (const group of tabGroups) {
for (const tab of group.tabs) {
if (tab.input instanceof vscode.TabInputText) {
const fileUri = tab.input.uri;
const filePath = fileUri.fsPath;
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, "utf-8");
// Escape any ']]>' sequences in content
const safeContent = content.replace(
/]]>/g,
"]]]]><![CDATA[>"
);

const fileName = path.relative(
vscode.workspace.workspaceFolders![0].uri.fsPath,
filePath
);

xmlContent += `<file name="${fileName}">
vscode.commands.registerCommand("files2prompt.copyOpenFiles", async () => {
const tabGroups: ReadonlyArray<vscode.TabGroup> =
vscode.window.tabGroups.all;

let xmlContent = "";

for (const group of tabGroups) {
for (const tab of group.tabs) {
if (tab.input instanceof vscode.TabInputText) {
const fileUri = tab.input.uri;
const filePath = fileUri.fsPath;
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, "utf-8");

const fileName = path.relative(
vscode.workspace.workspaceFolders![0].uri.fsPath,
filePath
);

xmlContent += `<file name="${fileName}">
<![CDATA[
${safeContent}
>
${content}
]]>
</file>
`;
}
}
}
}
}

if (xmlContent === "") {
vscode.window.showWarningMessage("No open files to copy.");
return;
}
if (xmlContent === "") {
vscode.window.showWarningMessage("No open files to copy.");
return;
}

const finalOutput = `<files>
const finalOutput = `<files>
${xmlContent}</files>`;

// Copy to clipboard
await vscode.env.clipboard.writeText(finalOutput);

vscode.window.showInformationMessage(
"Open file contents copied to clipboard."
);
}
)
await vscode.env.clipboard.writeText(finalOutput);
vscode.window.showInformationMessage(
"Open file contents copied to clipboard."
);
})
);

// Handle checkbox state changes asynchronously
treeView.onDidChangeCheckboxState(async (e) => {
for (const [item, state] of e.items) {
await fileTreeProvider.updateCheckState(item, state);
}
});

// Listen for configuration changes to update behavior dynamically
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration((event) => {
if (event.affectsConfiguration("files2prompt.systemMessage")) {
Expand All @@ -190,24 +162,20 @@ ${xmlContent}</files>`;

export function deactivate() { }

// Helper function to generate XML output
async function generateXmlOutput(filePaths: string[]): Promise<string> {
let xmlContent = "";

for (const filePath of filePaths) {
const content = fs.readFileSync(filePath, "utf-8");
// Escape any ']]>' sequences in file content
const safeContent = content.replace(/]]>/g, "]]]]><![CDATA[>");

const fileName = path.relative(
vscode.workspace.workspaceFolders![0].uri.fsPath,
filePath
);

xmlContent += `<file name="${fileName}">
<![CDATA[
${safeContent}
>
${content}
]]>
</file>
`;
}
Expand All @@ -216,7 +184,6 @@ ${safeContent}
${xmlContent}</files>`;
}

// Helper function to compare arrays of strings
function arraysEqual(a: string[], b: string[]): boolean {
if (a.length !== b.length) return false;
const sortedA = [...a].sort();
Expand All @@ -227,28 +194,16 @@ function arraysEqual(a: string[], b: string[]): boolean {
return true;
}

// Function to process XML content from clipboard
async function processXmlContent(xmlContent: string) {
// Extract only XML content
const xmlOnly = extractXmlContent(xmlContent);
if (!xmlOnly) {
vscode.window.showErrorMessage("No valid XML content found in clipboard.");
return;
}

const parser = new XMLParser({
ignoreAttributes: false,
allowBooleanAttributes: true,
parseTagValue: true,
parseAttributeValue: false,
trimValues: false,
cdataPropName: "__cdata",
tagValueProcessor: (val, tagName) => val, // Prevent default processing
trimValues: false
});

let jsonObj;
try {
jsonObj = parser.parse(xmlOnly);
jsonObj = parser.parse(xmlContent);
} catch (error) {
vscode.window.showErrorMessage("Error parsing XML content from clipboard.");
return;
Expand All @@ -270,7 +225,6 @@ async function processXmlContent(xmlContent: string) {
if (fileObj["__cdata"]) {
fileContent = fileObj["__cdata"];
} else {
// If no CDATA, get text content
fileContent = fileObj["#text"] || "";
}

Expand All @@ -285,14 +239,4 @@ async function processXmlContent(xmlContent: string) {
}

vscode.window.showInformationMessage("Files have been updated successfully.");
}

function extractXmlContent(text: string): string | null {
const xmlMatch = text.match(/<files>[\s\S]*<\/files>/);
if (xmlMatch) {
return xmlMatch[0];
}

// If no <files> tag found, return null
return null;
}
}

0 comments on commit 0b85226

Please sign in to comment.