Merge pull request #576 from devchat-ai/support_edit_apply_action
feat: Add code editing, diff display, and CORS support
This commit is contained in:
commit
7ab27f77c8
@ -1,5 +1,8 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
import { createTempSubdirectory } from '../util/commonUtil';
|
import { createTempSubdirectory } from '../util/commonUtil';
|
||||||
import { regInMessage, regOutMessage } from '../util/reg_messages';
|
import { regInMessage, regOutMessage } from '../util/reg_messages';
|
||||||
@ -8,6 +11,7 @@ import { logger } from '../util/logger';
|
|||||||
import { FilePairManager } from '../util/diffFilePairs';
|
import { FilePairManager } from '../util/diffFilePairs';
|
||||||
import { UiUtilWrapper } from '../util/uiUtil';
|
import { UiUtilWrapper } from '../util/uiUtil';
|
||||||
import { getFileContent } from '../util/commonUtil';
|
import { getFileContent } from '../util/commonUtil';
|
||||||
|
import { ExtensionContextHolder } from '@/util/extensionContext';
|
||||||
|
|
||||||
|
|
||||||
async function getDocumentText(): Promise<{ text: string; beforSelect: string; select: string, afterSelect: string } | undefined> {
|
async function getDocumentText(): Promise<{ text: string; beforSelect: string; select: string, afterSelect: string } | undefined> {
|
||||||
@ -106,6 +110,105 @@ async function getNewCode(message: any): Promise<string | undefined> {
|
|||||||
return newCode;
|
return newCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCodeEditorPath() {
|
||||||
|
const platform = os.platform();
|
||||||
|
const arch = os.arch();
|
||||||
|
|
||||||
|
let binaryName;
|
||||||
|
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
if (arch === 'arm64') {
|
||||||
|
binaryName = 'aarch64-apple-darwin-code_editor';
|
||||||
|
} else if (arch === 'x64') {
|
||||||
|
binaryName = 'x86_64-apple-darwin-code_editor';
|
||||||
|
}
|
||||||
|
} else if (platform === 'win32' && arch === 'x64') {
|
||||||
|
binaryName = 'x86_64-pc-windows-msvc-code_editor.exe';
|
||||||
|
} else if (platform === 'linux' && arch === 'x64') {
|
||||||
|
binaryName = 'x86_64-unknown-linux-musl-code_editor';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!binaryName) {
|
||||||
|
logger.channel()?.error(`Error: No matching binary for platform ${platform} and architecture ${arch}`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.join(UiUtilWrapper.extensionPath(), 'tools', 'code-editor', binaryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyDiffToCode(message: any): Promise<string | undefined> {
|
||||||
|
const validVisibleTextEditors = vscode.window.visibleTextEditors.filter(editor => editor.viewColumn !== undefined);
|
||||||
|
|
||||||
|
if (validVisibleTextEditors.length > 1) {
|
||||||
|
vscode.window.showErrorMessage(`There are more then one visible text editors. Please close all but one and try again.`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const editor = validVisibleTextEditors[0];
|
||||||
|
if (!editor) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get whole text in editor
|
||||||
|
const srcCode = editor.document.getText();
|
||||||
|
let newCode = message.content;
|
||||||
|
|
||||||
|
// Create temporary files
|
||||||
|
const tempDir = os.tmpdir();
|
||||||
|
const srcTempFile = path.join(tempDir, 'temp_file_1');
|
||||||
|
const newTempFile = path.join(tempDir, 'temp_file_2');
|
||||||
|
const resultTempFile = path.join(tempDir, 'result_temp_file');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Save srcCode and newCode to temp files
|
||||||
|
await fs.promises.writeFile(srcTempFile, srcCode);
|
||||||
|
await fs.promises.writeFile(newTempFile, newCode);
|
||||||
|
|
||||||
|
// Call the code_editor process
|
||||||
|
const codeEditorPath = getCodeEditorPath();
|
||||||
|
if (!codeEditorPath) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 Promise 包装 exec 调用,以获取退出码
|
||||||
|
const execWithExitCode = () => new Promise<{ exitCode: number | null, stdout: string, stderr: string }>((resolve, reject) => {
|
||||||
|
exec(`${codeEditorPath} ${srcTempFile} ${newTempFile} ${resultTempFile}`, (error, stdout, stderr) => {
|
||||||
|
if (error && 'code' in error) {
|
||||||
|
// error 是 ExecException 类型
|
||||||
|
resolve({ exitCode: error.code || 1, stdout, stderr });
|
||||||
|
} else if (error) {
|
||||||
|
// 其他类型的错误
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
resolve({ exitCode: 0, stdout, stderr });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const { exitCode, stdout, stderr } = await execWithExitCode();
|
||||||
|
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
logger.channel()?.error(`Error executing code_editor. Exit code: ${exitCode}. Stderr: ${stderr}`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the result from the temp file
|
||||||
|
newCode = await fs.promises.readFile(resultTempFile, 'utf-8');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error in applyDiffToCode: ${error}`);
|
||||||
|
return undefined;
|
||||||
|
} finally {
|
||||||
|
// Clean up temporary files
|
||||||
|
await Promise.all([
|
||||||
|
fs.promises.unlink(srcTempFile).catch(() => {}),
|
||||||
|
fs.promises.unlink(newTempFile).catch(() => {}),
|
||||||
|
fs.promises.unlink(resultTempFile).catch(() => {})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newCode;
|
||||||
|
}
|
||||||
|
|
||||||
regInMessage({ command: 'show_diff', content: '', fileName: '' });
|
regInMessage({ command: 'show_diff', content: '', fileName: '' });
|
||||||
export async function applyCodeWithDiff(message: any, panel: vscode.WebviewPanel | vscode.WebviewView | undefined): Promise<void> {
|
export async function applyCodeWithDiff(message: any, panel: vscode.WebviewPanel | vscode.WebviewView | undefined): Promise<void> {
|
||||||
const newCode = await getNewCode(message);
|
const newCode = await getNewCode(message);
|
||||||
@ -116,3 +219,14 @@ export async function applyCodeWithDiff(message: any, panel: vscode.WebviewPanel
|
|||||||
diffView(newCode, message.fileName);
|
diffView(newCode, message.fileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regInMessage({ command: 'apply_with_diff', content: '', fileName: '' });
|
||||||
|
export async function applyEditCodeWithDiff(message: any, panel: vscode.WebviewPanel | vscode.WebviewView | undefined): Promise<void> {
|
||||||
|
const newCode = await applyDiffToCode(message);
|
||||||
|
if (!newCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diffView(newCode, message.fileName);
|
||||||
|
return;
|
||||||
|
}
|
@ -1,11 +1,15 @@
|
|||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { applyCodeWithDiff } from "../../handler/diffHandler";
|
import { applyCodeWithDiff, applyEditCodeWithDiff } from "../../handler/diffHandler";
|
||||||
import { getSymbolDefines } from "../../context/contextRefDefs";
|
import { getSymbolDefines } from "../../context/contextRefDefs";
|
||||||
|
|
||||||
|
|
||||||
export namespace UnofficialEndpoints {
|
export namespace UnofficialEndpoints {
|
||||||
export async function diffApply(filepath: string, content: string) {
|
export async function diffApply(filepath: string, content: string, autoedit: boolean = false) {
|
||||||
applyCodeWithDiff({ fileName: filepath, content: content }, undefined);
|
if (autoedit) {
|
||||||
|
applyEditCodeWithDiff({ fileName: filepath, content: content }, undefined)
|
||||||
|
} else {
|
||||||
|
applyCodeWithDiff({ fileName: filepath, content: content }, undefined);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ const functionRegistry: any = {
|
|||||||
handler: () => "vscode",
|
handler: () => "vscode",
|
||||||
},
|
},
|
||||||
"/diff_apply": {
|
"/diff_apply": {
|
||||||
keys: ["filepath", "content"],
|
keys: ["filepath", "content", "autoedit"],
|
||||||
handler: UnofficialEndpoints.diffApply,
|
handler: UnofficialEndpoints.diffApply,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -126,6 +126,12 @@ export async function startRpcServer() {
|
|||||||
|
|
||||||
let params: any = {};
|
let params: any = {};
|
||||||
|
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.writeHead(200, { "Content-Type": "application/json" });
|
||||||
|
res.end(JSON.stringify({"status": "ok"}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (req.method === "POST") {
|
if (req.method === "POST") {
|
||||||
let body = "";
|
let body = "";
|
||||||
req.on("data", (chunk) => {
|
req.on("data", (chunk) => {
|
||||||
|
2
tools
2
tools
@ -1 +1 @@
|
|||||||
Subproject commit c4f335e486a33f8161d4866b1d0e5600391a0434
|
Subproject commit bb071a9bd97a04ab9190be2ed96fb0e7a539b073
|
Loading…
x
Reference in New Issue
Block a user