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
|
import * as os from "os";
import * as path from "path";
import * as fs from "fs";
import * as vscode from "vscode";
interface DiffInfo {
originalFilepath: string;
newFilepath: string;
editor?: vscode.TextEditor;
}
export const DIFF_DIRECTORY = path.join(os.homedir(), ".continue", "diffs");
class DiffManager {
// Create a temporary file in the global .continue directory which displays the updated version
// Doing this because virtual files are read-only
private diffs: Map<string, DiffInfo> = new Map();
constructor() {
// Make sure the diff directory exists
if (!fs.existsSync(DIFF_DIRECTORY)) {
fs.mkdirSync(DIFF_DIRECTORY, {
recursive: true,
});
}
}
private escapeFilepath(filepath: string): string {
return filepath.replace(/\\/g, "_").replace(/\//g, "_");
}
private openDiffEditor(
originalFilepath: string,
newFilepath: string,
newContent: string
): vscode.TextEditor {
const rightUri = vscode.Uri.parse(newFilepath);
const leftUri = vscode.Uri.file(originalFilepath);
const title = "Continue Diff";
vscode.commands.executeCommand("vscode.diff", leftUri, rightUri, title);
const editor = vscode.window.activeTextEditor;
if (!editor) {
throw new Error("No active text editor found for Continue Diff");
}
return editor;
}
writeDiff(originalFilepath: string, newContent: string): string {
// Create or update existing diff
const newFilepath = path.join(
DIFF_DIRECTORY,
this.escapeFilepath(originalFilepath)
);
fs.writeFileSync(newFilepath, newContent);
// Open the diff editor if this is a new diff
if (!this.diffs.has(originalFilepath)) {
const diffInfo: DiffInfo = {
originalFilepath,
newFilepath,
};
diffInfo.editor = this.openDiffEditor(
originalFilepath,
newFilepath,
newContent
);
this.diffs.set(originalFilepath, diffInfo);
}
return newFilepath;
}
cleanUpDiff(diffInfo: DiffInfo) {
// Close the editor, remove the record, delete the file
if (diffInfo.editor) {
vscode.window.showTextDocument(diffInfo.editor.document);
vscode.commands.executeCommand("workbench.action.closeActiveEditor");
}
this.diffs.delete(diffInfo.originalFilepath);
fs.unlinkSync(diffInfo.newFilepath);
}
acceptDiff(originalFilepath: string) {
// Get the diff info, copy new file to original, then delete from record and close the corresponding editor
const diffInfo = this.diffs.get(originalFilepath);
if (!diffInfo) {
return;
}
fs.writeFileSync(
diffInfo.originalFilepath,
fs.readFileSync(diffInfo.newFilepath)
);
this.cleanUpDiff(diffInfo);
}
rejectDiff(originalFilepath: string) {
const diffInfo = this.diffs.get(originalFilepath);
if (!diffInfo) {
return;
}
this.cleanUpDiff(diffInfo);
}
}
export const diffManager = new DiffManager();
export async function acceptDiffCommand(originalFilepath: string) {
diffManager.acceptDiff(originalFilepath);
}
export async function rejectDiffCommand(originalFilepath: string) {
diffManager.rejectDiff(originalFilepath);
}
|