diff --git a/assets/clipboard.js b/assets/clipboard.js index a58a5fd..ba0a746 100644 --- a/assets/clipboard.js +++ b/assets/clipboard.js @@ -32,7 +32,7 @@ function initClipboard(codeBlocks, onApplyButtonClick, onApplyCodeButtonClick, o // Add 'Apply' button const applyButton = document.createElement('button'); applyButton.classList.add('apply-button'); - applyButton.innerText = 'Apply Patch'; + applyButton.innerText = 'Show Diff'; block.appendChild(applyButton); applyButton.addEventListener('click', () => { diff --git a/instructions/instCommitMessage.txt b/instructions/commit_message/instCommitMessage.txt similarity index 100% rename from instructions/instCommitMessage.txt rename to instructions/commit_message/instCommitMessage.txt diff --git a/instructions/instCode.txt b/instructions/default/instCode.txt similarity index 100% rename from instructions/instCode.txt rename to instructions/default/instCode.txt diff --git a/instructions/instLangPython.txt b/instructions/default/instLangPython.txt similarity index 100% rename from instructions/instLangPython.txt rename to instructions/default/instLangPython.txt diff --git a/instructions/instCommon.txt b/instructions/instCommon.txt deleted file mode 100644 index 1a1b2df..0000000 --- a/instructions/instCommon.txt +++ /dev/null @@ -1 +0,0 @@ -You are a software developer assistant. \ No newline at end of file diff --git a/package.json b/package.json index 38e6ed0..583d942 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,41 @@ "README.md" ], "contributes": { + "configuration": { + "title": "DevChat", + "properties": { + "DevChat.llmModel": { + "type": "string", + "default": "OpenAI", + "enum": ["OpenAI"], + "description": "Select whose llm to use." + }, + "DevChat.OpenAI.model": { + "type": "string", + "default": "gpt-4", + "description": "Specify llm model", + "when": "DevChat.llmModel == 'OpenAI'" + }, + "DevChat.OpenAI.temperature": { + "type": "number", + "default": 0.2, + "description": "Specify llm temperature", + "when": "DevChat.llmModel == 'OpenAI'" + }, + "DevChat.OpenAI.stream": { + "type": "boolean", + "default": true, + "description": "Specify llm stream", + "when": "DevChat.llmModel == 'OpenAI'" + }, + "DevChat.OpenAI.apiKey": { + "type": "string", + "default": "", + "description": "Open API Key", + "when": "DevChat.llmModel == 'OpenAI'" + } + } + }, "views": { "explorer": [ { diff --git a/src/applyCode.ts b/src/applyCode.ts index f227b40..9384ab2 100644 --- a/src/applyCode.ts +++ b/src/applyCode.ts @@ -1,4 +1,6 @@ const vscode = require('vscode'); +import * as path from 'path'; +import { createTempSubdirectory } from './commonUtil'; export async function applyCodeFile(text: string) { @@ -23,7 +25,7 @@ export async function applyCodeFile(text: string) { }); } -async function applyCode(text: string) { +export async function applyCode(text: string) { if (vscode.window.visibleTextEditors.length > 1) { vscode.window.showErrorMessage(`There are more then one visible text editors. Please close all but one and try again.`); return; @@ -43,4 +45,43 @@ async function applyCode(text: string) { }); } - export default applyCode; \ No newline at end of file +export async function diffView(code: string) { + if (vscode.window.visibleTextEditors.length > 1) { + vscode.window.showErrorMessage(`There are more then one visible text editors. Please close all but one and try again.`); + return; + } + + const editor = vscode.window.visibleTextEditors[0]; + if (!editor) { + return; + } + + const selectedText = editor.document.getText(editor.selection); + + const curFile = editor.document.fileName; + + // get file name from fileSelected + const fileName = path.basename(curFile); + + // create temp directory and file + const tempDir = await createTempSubdirectory('devchat/context'); + const tempFile = path.join(tempDir, fileName); + + // save code to temp file + await vscode.workspace.fs.writeFile(vscode.Uri.file(tempFile), Buffer.from(code)); + + if (selectedText) { + // create temp directory and file + const tempDir = await createTempSubdirectory('devchat/context'); + const tempSelectCodeFile = path.join(tempDir, fileName); + + // save code to temp file + await vscode.workspace.fs.writeFile(vscode.Uri.file(tempSelectCodeFile), Buffer.from(selectedText)); + + // open diff view + vscode.commands.executeCommand('vscode.diff', vscode.Uri.file(tempSelectCodeFile), vscode.Uri.file(tempFile), 'Diff View'); + } else { + // open diff view + vscode.commands.executeCommand('vscode.diff', vscode.Uri.file(curFile), vscode.Uri.file(tempFile), 'Diff View'); + } + } diff --git a/src/commitMessageCommand.ts b/src/commitMessageCommand.ts index 3796e83..2e9057b 100644 --- a/src/commitMessageCommand.ts +++ b/src/commitMessageCommand.ts @@ -44,15 +44,22 @@ async function writeDiffFile(diff_file: string) { export const commitMessageCommand: Command = { name: 'commitMessageCommand', - pattern: 'git: commit message', + pattern: 'commit_meesage', description: 'commit message for changes', handler: async (userInput: string) => { const tempDir = createTempSubdirectory('devchat/context'); - // 创建临时目录 - const diff_file = path.join(tempDir, 'diff_output.txt'); - await writeDiffFile(diff_file); + // // 创建临时目录 + // const diff_file = path.join(tempDir, 'diff_output.txt'); + // await writeDiffFile(diff_file); - return `[context|${diff_file}] Write a commit message`; + // return `[context|${diff_file}] Write a commit message`; + + const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath; + if (workspaceDir) { + const commitmessageInstruction = path.join(workspaceDir, '.chat', 'instructions', 'commit_message', 'instCommitMessage.txt'); + return `[instruction|${commitmessageInstruction}] Write a commit message`; + } + return 'Write a commit message'; }, }; diff --git a/src/devchat.ts b/src/devchat.ts index a249a19..2a9b381 100644 --- a/src/devchat.ts +++ b/src/devchat.ts @@ -5,6 +5,7 @@ import { promisify } from "util"; import * as vscode from 'vscode'; import * as dotenv from 'dotenv'; import * as path from 'path'; +import * as fs from 'fs'; const spawnAsync = async (command: string, args: string[], options: any, onData: (data: string) => void): Promise<{code: number, stdout: string; stderr: string }> => { return new Promise((resolve, reject) => { @@ -82,7 +83,28 @@ class DevChat { args.push(content) const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath; - const openaiApiKey = process.env.OPENAI_API_KEY; + // const openaiApiKey = process.env.OPENAI_API_KEY; + + const openaiApiKey = vscode.workspace.getConfiguration('DevChat').get('OpenAI.apiKey'); + + const openaiModel = vscode.workspace.getConfiguration('DevChat').get('OpenAI.model'); + const openaiTemperature = vscode.workspace.getConfiguration('DevChat').get('OpenAI.temperature'); + const openaiStream = vscode.workspace.getConfiguration('DevChat').get('OpenAI.stream'); + const llmModel = vscode.workspace.getConfiguration('DevChat').get('llmModel'); + + const devchatConfig = { + llm: llmModel, + OpenAI: { + model: openaiModel, + temperature: openaiTemperature, + stream: openaiStream + } + } + // write to config file + const configPath = path.join(workspaceDir!, '.chatconfig.json'); + // write devchatConfig to configPath + const configJson = JSON.stringify(devchatConfig, null, 2); + fs.writeFileSync(configPath, configJson); try { const {code, stdout, stderr } = await spawnAsync('devchat', args, { diff --git a/src/messageHandler.ts b/src/messageHandler.ts index ed66670..9417255 100644 --- a/src/messageHandler.ts +++ b/src/messageHandler.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import { promisify } from 'util'; import DevChat, { LogOptions } from './devchat'; import DtmWrapper from './dtm'; -import applyCode, {applyCodeFile} from './applyCode'; +import {applyCodeFile, diffView, applyCode} from './applyCode'; import './loadCommands'; import './loadContexts' @@ -87,7 +87,7 @@ function getInstructionFiles(): string[] { const instructionFiles: string[] = []; const workspaceDir = vscode.workspace.workspaceFolders?.[0].uri.fsPath; if (workspaceDir) { - const chatInstructionsPath = path.join(workspaceDir, '.chat', 'instructions'); + const chatInstructionsPath = path.join(workspaceDir, '.chat', 'instructions', 'default'); try { // 读取 chatInstructionsPath 目录下的所有文件和目录 const files = fs.readdirSync(chatInstructionsPath); @@ -126,6 +126,9 @@ async function handleMessage( } chatOptions.header = getInstructionFiles(); + if (parsedMessage.instruction.length > 0) { + chatOptions.header = parsedMessage.instruction; + } if (parsedMessage.reference.length > 0) { chatOptions.reference = parsedMessage.reference; @@ -147,20 +150,12 @@ async function handleMessage( const logEntries = await devChat.log(logOptions); panel.webview.postMessage({ command: 'loadHistoryMessages', entries: logEntries }); return; + case 'show_diff': + diffView(message.content); + return; + // TODO: remove block_apply case 'block_apply': - const tempPatchFile = await saveTempPatchFile(message.content); - try { - const patchResult = await dtmWrapper.patch(tempPatchFile); - await deleteTempPatchFile(tempPatchFile); - if (patchResult.status === 0) { - vscode.window.showInformationMessage('Patch applied successfully.'); - } else { - vscode.window.showErrorMessage(`Error applying patch: ${patchResult.message} ${patchResult.log}`); - } - } catch (error) { - await deleteTempPatchFile(tempPatchFile); - vscode.window.showErrorMessage(`Error applying patch: ${error}`); - } + diffView(message.content); return; case 'code_apply': await applyCode(message.content);