Merge branch 'main' into auto_custom_workflow

This commit is contained in:
Rankin Zheng 2024-09-02 15:49:27 +08:00
commit cb11ec567e
16 changed files with 157 additions and 157 deletions

7
.env.example Normal file
View File

@ -0,0 +1,7 @@
EXTENSION_NAME=devchat
PUBLISHER=merico
ASSISTANT_NAME_EN=DevChat
ASSISTANT_NAME_ZH=DevChat
EXTENSION_ICON=/path/to/extension_icon.png
SIDEBAR_ICON=/path/to/sidebar_icon.svg
DIFF_APPLY_ICON=/path/to/diff_apply_icon.svg

1
.gitignore vendored
View File

@ -15,3 +15,4 @@ actions_backup/
.DS_Store
__pycache__/
*.log

1
.vscode/launch.json vendored
View File

@ -16,6 +16,7 @@
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "${defaultBuildTask}",
"postDebugTask": "npm: postbuild",
"env": {
"COMPLETE_DEBUG": "true"
}

7
.vscode/tasks.json vendored
View File

@ -35,6 +35,13 @@
"npm: watch-tests"
],
"problemMatcher": []
},
{
"type": "npm",
"script": "postbuild",
"problemMatcher": [],
"label": "npm: postbuild",
"detail": "npm run postbuild"
}
]
}

View File

@ -1,13 +1,17 @@
{
"name": "devchat",
"displayName": "DevChat",
"displayName": "${ASSISTANT_NAME_ZH}",
"description": "Write prompts, not code",
"version": "0.1.74",
"icon": "assets/devchat.png",
"publisher": "merico",
"publisher": "${PUBLISHER}",
"engines": {
"vscode": "^1.75.0"
},
"assistantNames": {
"ASSISTANT_NAME_EN": "${ASSISTANT_NAME_EN}",
"ASSISTANT_NAME_ZH": "${ASSISTANT_NAME_ZH}"
},
"repository": {
"type": "git",
"url": "https://github.com/devchat-ai/devchat-vscode.git"
@ -72,7 +76,7 @@
"activitybar": [
{
"id": "devchat-sidebar",
"title": "DevChat",
"title": "${ASSISTANT_NAME_ZH}",
"icon": "assets/devchat_icon.svg"
}
]
@ -82,7 +86,7 @@
{
"type": "webview",
"id": "devchat-view",
"name": "DevChat"
"name": "${ASSISTANT_NAME_ZH}"
}
]
},
@ -103,27 +107,27 @@
},
{
"command": "devchat.addContext",
"title": "Devchat:Add to DevChat"
"title": "${ASSISTANT_NAME_EN}:Add to ${ASSISTANT_NAME_EN}"
},
{
"command": "devchat.askForCode",
"title": "Devchat:Add to DevChat"
"title": "${ASSISTANT_NAME_EN}:Add to ${ASSISTANT_NAME_EN}"
},
{
"command": "devchat.askForFile",
"title": "Devchat:Add to DevChat"
"title": "${ASSISTANT_NAME_EN}:Add to ${ASSISTANT_NAME_EN}"
},
{
"command": "devchat.addConext_chinese",
"title": "Devchat:添加到DevChat"
"title": "${ASSISTANT_NAME_ZH}:添加到${ASSISTANT_NAME_ZH}"
},
{
"command": "devchat.askForCode_chinese",
"title": "Devchat:添加到DevChat"
"title": "${ASSISTANT_NAME_ZH}:添加到${ASSISTANT_NAME_ZH}"
},
{
"command": "devchat.askForFile_chinese",
"title": "Devchat:添加到DevChat"
"title": "${ASSISTANT_NAME_ZH}:添加到${ASSISTANT_NAME_ZH}"
},
{
"command": "DevChat.InstallCommands",
@ -137,32 +141,32 @@
},
{
"command": "DevChat.Chat",
"title": "Chat with DevChat",
"title": "Chat with ${ASSISTANT_NAME_EN}",
"category": "DevChat"
},
{
"command": "devchat.explain",
"title": "Devchat:Generate Explain"
"title": "${ASSISTANT_NAME_EN}:Generate Explain"
},
{
"command": "devchat.explain_chinese",
"title": "Devchat:代码解释"
"title": "${ASSISTANT_NAME_ZH}:代码解释"
},
{
"command": "devchat.comments",
"title": "Devchat:Generate Comments"
"title": "${ASSISTANT_NAME_EN}:Generate Comments"
},
{
"command": "devchat.comments_chinese",
"title": "Devchat:生成注释"
"title": "${ASSISTANT_NAME_ZH}:生成注释"
},
{
"command": "devchat.fix",
"title": "Devchat:Fix this"
"title": "${ASSISTANT_NAME_EN}:Fix this"
},
{
"command": "devchat.fix_chinese",
"title": "Devchat:修复此"
"title": "${ASSISTANT_NAME_ZH}:修复此"
},
{
"command": "DevChat.codecomplete_callback",
@ -171,12 +175,12 @@
},
{
"command": "DevChat.quickFixAskDevChat",
"title": "Ask DevChat",
"title": "Ask ${ASSISTANT_NAME_EN}",
"category": "DevChat"
},
{
"command": "DevChat.quickFixUsingDevChat",
"title": "Ask DevChat",
"title": "Ask ${ASSISTANT_NAME_EN}",
"category": "DevChat"
}
],
@ -340,20 +344,21 @@
}
},
"scripts": {
"build:gui": "cd ./gui && yarn && yarn vscode",
"vscode:uninstall": "node ./dist/uninstall",
"vscode:prepublish": "npm run package",
"compile": "webpack",
"watch": "webpack --watch",
"package": "webpack --mode production --devtool hidden-source-map",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"vscode:prepublish": "node prebuild.js && webpack --mode production --devtool hidden-source-map",
"prebuild": "node prebuild.js",
"postbuild": "git checkout -- assets package.json",
"build:gui": "cd ./gui && yarn && yarn vscode",
"build": "webpack --config webpack.config.js && npm run build:gui",
"postpackage": "git checkout -- assets package.json",
"package": "vsce package",
"dev": "webpack serve --config webpack.config.js --open",
"watch": "npm run prebuild && webpack --watch",
"lint": "eslint src --ext ts",
"test": "mocha",
"build": "webpack --config webpack.config.js && cd ./gui && yarn && yarn vscode",
"dev": "webpack serve --config webpack.config.js --open",
"idea": "webpack --config webpack.idea.config.js && mv dist/main.js dist/main.html ../devchat-intellij/src/main/resources/static && echo '🎆done'"
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "npm run prebuild && tsc -p . -w --outDir out"
},
"devDependencies": {
"@babel/core": "^7.21.8",

51
prebuild.js Normal file
View File

@ -0,0 +1,51 @@
require('dotenv').config()
const fs = require('fs')
const path = require('path')
function copyIcon(src, dst) {
if (!src) {
console.warn(`Icon path for ${dst} is not defined in your environment variables`)
return
}
console.log(`Replacing icon ${dst} by ${src}`)
if (!fs.existsSync(src)) {
console.warn(`Icon file ${src} does not exist.`)
return
}
const destPath = path.join(__dirname, 'assets', dst)
try {
fs.copyFileSync(src, destPath)
fs.chmodSync(destPath, 0o644)
} catch(e) {
console.warn(`Failed to copy logo ${e}`)
}
}
function updatePackageJson() {
const placeholders = {
EXTENSION_NAME: process.env.EXTENSION_NAME || "devchat",
PUBLISHER: process.env.PUBLISHER || "merico",
ASSISTANT_NAME_EN: process.env.ASSISTANT_NAME_EN || "DevChat",
ASSISTANT_NAME_ZH: process.env.ASSISTANT_NAME_ZH || "DevChat"
}
console.log(`Updating package.json, env: ${JSON.stringify(placeholders)}`)
let packageJson = fs.readFileSync('package.json', 'utf8');
// Replace placeholders
Object.entries(placeholders).forEach(([key, value]) => {
const regex = new RegExp(`\\$\\{${key}\\}`, 'g');
packageJson = packageJson.replace(regex, value);
});
fs.writeFileSync('package.json', packageJson);
}
copyIcon(process.env.EXTENSION_ICON, 'devchat.png')
copyIcon(process.env.SIDEBAR_ICON, 'devchat_icon.svg')
copyIcon(process.env.DIFF_APPLY_ICON, 'devchat_apply.svg')
updatePackageJson()

View File

@ -1,5 +1,6 @@
import * as vscode from "vscode";
import { collapseFileExculdeSelectRange } from "./codecomplete/ast/collapseBlock";
import { ASSISTANT_NAME_EN } from "../util/constants";
class DevChatQuickFixProvider implements vscode.CodeActionProvider {
public static readonly providedCodeActionKinds = [
@ -18,13 +19,13 @@ class DevChatQuickFixProvider implements vscode.CodeActionProvider {
const diagnostic = context.diagnostics[0];
const quickFix = new vscode.CodeAction(
"Ask DevChat",
`Ask ${ASSISTANT_NAME_EN}`,
vscode.CodeActionKind.QuickFix,
);
quickFix.isPreferred = false;
const fixUsingDevChat = new vscode.CodeAction(
"Fix using DevChat",
`Fix using ${ASSISTANT_NAME_EN}`,
vscode.CodeActionKind.QuickFix,
);
fixUsingDevChat.isPreferred = true;
@ -32,7 +33,7 @@ class DevChatQuickFixProvider implements vscode.CodeActionProvider {
return new Promise(async (resolve) => {
quickFix.command = {
command: "DevChat.quickFixAskDevChat",
title: "Ask DevChat",
title: `Ask ${ASSISTANT_NAME_EN}`,
arguments: [
document,
range,
@ -42,7 +43,7 @@ class DevChatQuickFixProvider implements vscode.CodeActionProvider {
fixUsingDevChat.command = {
command: "DevChat.quickFixUsingDevChat",
title: "Fix using DevChat",
title: `Fix using ${ASSISTANT_NAME_EN}`,
arguments: [
document,
range,

View File

@ -35,6 +35,7 @@ import { InlineCompletionProvider, registerCodeCompleteCallbackCommand } from ".
import { indexDir } from "./contributes/codecomplete/astIndex";
import registerQuickFixProvider from "./contributes/quickFixProvider";
import { stopLocalService } from './util/localService';
import { updateNames } from "./util/constants";
async function migrateConfig() {
@ -129,6 +130,8 @@ export async function fixDevChatApiBase() {
async function activate(context: vscode.ExtensionContext) {
ExtensionContextHolder.context = context;
const assistantNames = context.extension.packageJSON.assistantNames
updateNames(assistantNames.ASSISTANT_NAME_EN, assistantNames.ASSISTANT_NAME_ZH)
logger.init(LoggerChannelVscode.getInstance());
UiUtilWrapper.init(new UiUtilVscode());

View File

@ -1,3 +1,4 @@
import { ASSISTANT_NAME_EN } from '../util/constants';
import { UiUtilWrapper } from '../util/uiUtil';
import { MessageHandler } from './messageHandler';
import { isSending } from './sendMessage';
@ -6,7 +7,7 @@ import { isSending } from './sendMessage';
export async function chatWithDevChat(panel, message: string) {
if (isSending()) {
// already sending, show error
UiUtilWrapper.showErrorMessage("DevChat: A command is already being sent, please try again later.");
UiUtilWrapper.showErrorMessage(`${ASSISTANT_NAME_EN}: A command is already being sent, please try again later.`);
return;
}
MessageHandler.sendMessage(panel!, { command: 'chatWithDevChat', 'message': message });

View File

@ -18,42 +18,6 @@ export interface LoadHistoryMessages {
entries: Array<LogEntry>;
}
function welcomeMessage(): LogEntry {
// create default logEntry to show welcome message
return {
hash: 'message',
parent: '',
user: 'system',
date: '',
request: 'How do I use DevChat?',
response: `
Do you want to write some code or have a question about the project? Simply right-click on your chosen files or code snippets and add them to DevChat. Feel free to ask me anything or let me help you with coding.
Don't forget to check out the "+" button on the left of the input to add more context. To see a list of workflows you can run in the context, just type "/". Happy prompting!
`,
context: []
} as LogEntry;
}
function apiKeyMissedMessage(): LogEntry {
// create default logEntry to show welcome message
return {
hash: 'message',
parent: '',
user: 'system',
date: '',
request: 'Is OPENAI_API_KEY (or DevChat Access Key) ready?',
response: `
OPENAI_API_KEY is missing from your environment or settings. Kindly input your OpenAI or DevChat key, and I'll ensure DevChat is all set for you.
<button value="get_devchat_key" href="https://web.devchat.ai" component="a">Register DevChat key</button>
<button value="setting_devchat_key">Set DevChat key</button>
<button value="setting_openai_key">Set OpenAI key</button>
`,
context: []
} as LogEntry;
}
async function loadTopicHistoryLogs(topicId: string | undefined): Promise<Array<LogEntry> | undefined> {
if (!topicId) {
return undefined;

View File

@ -1,8 +1,7 @@
import * as vscode from "vscode";
import * as fs from "fs";
import * as path from "path";
import { logger } from "../util/logger";
import { log } from "console";
import { ASSISTANT_NAME_ZH } from "../util/constants";
import { ExtensionContextHolder } from "../util/extensionContext";
interface FunctionDefinition {
name: string;
@ -19,42 +18,10 @@ type CodeLensRegistration = {
export class CodeLensManager {
private static instance: CodeLensManager;
private registrations: CodeLensRegistration[] = [];
private configFilePath: string;
private constructor() {
this.configFilePath = path.join(
process.env.HOME || process.env.USERPROFILE || ".",
".chat/ideconfig.json"
);
this.loadConfig();
}
public static getInstance(): CodeLensManager {
if (!CodeLensManager.instance) {
CodeLensManager.instance = new CodeLensManager();
}
return CodeLensManager.instance;
}
private loadConfig(): void {
if (!fs.existsSync(this.configFilePath)) {
this.initializeConfig();
} else {
const data = fs.readFileSync(this.configFilePath, "utf-8");
this.registrations = JSON.parse(data);
if (this.registrations.length === 0) {
this.initializeConfig();
}
}
}
private initializeConfig(): void {
this.registrations = [
private registrations: CodeLensRegistration[] = [
{
elementType: "function",
objectName: "DevChat: unit tests",
objectName: `${ExtensionContextHolder.context?.extension.packageJSON.assistantNames.ASSISTANT_NAME_ZH}: unit tests`,
promptGenerator:
"/unit_tests {__filename__}:::{__functionName__}:::{__functionStartLine__}:::{__functionEndLine__}:::{__containerStartLine__}:::{__containerEndLine__}",
},
@ -68,36 +35,17 @@ export class CodeLensManager {
objectName: "docstring",
promptGenerator: "/docstring",
},
// {
// elementType: 'function',
// objectName: 'generate unit tests',
// promptGenerator: '/test generate unit tests for {__filename__} {__functionName__}'
// },
// {
// elementType: 'inner_function',
// objectName: 'generate comment',
// promptGenerator: 'generate comment for \n ```code\n{__functionCode__}\n```\n'
// },
// {
// elementType: 'function',
// objectName: 'generate comment',
// promptGenerator: 'generate comment for \n ```code\n{__functionCode__}\n```\n'
// }
];
this.saveConfig();
private constructor() {}
public static getInstance(): CodeLensManager {
if (!CodeLensManager.instance) {
CodeLensManager.instance = new CodeLensManager();
}
return CodeLensManager.instance;
}
private saveConfig(): void {
const configDir = path.dirname(this.configFilePath);
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
}
fs.writeFileSync(
this.configFilePath,
JSON.stringify(this.registrations, null, 2),
"utf8"
);
}
public getRegistrations(): CodeLensRegistration[] {
return this.registrations;

View File

@ -2,16 +2,15 @@ import * as vscode from 'vscode';
import { dependencyCheck } from './statusBarViewBase';
import { ProgressBar } from '../util/progressBar';
import { logger } from '../util/logger';
import { DevChatConfig } from '../util/config';
import { ASSISTANT_NAME_EN } from '../util/constants';
export function createStatusBarItem(context: vscode.ExtensionContext): vscode.StatusBarItem {
const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
// Set the status bar item properties
statusBarItem.text = `$(warning)DevChat`;
statusBarItem.tooltip = 'DevChat is checking ..., please wait';
statusBarItem.text = `$(warning)${ASSISTANT_NAME_EN}`;
statusBarItem.tooltip = `${ASSISTANT_NAME_EN} is checking ..., please wait`;
// when statsBarItem.command is '', then there is "command '' not found" error.
statusBarItem.command = undefined;
@ -27,8 +26,8 @@ export function createStatusBarItem(context: vscode.ExtensionContext): vscode.St
progressBar.update("Checking dependencies", 0);
const devchatStatus = await dependencyCheck();
if (devchatStatus !== 'has statisfied the dependency' && devchatStatus !== 'DevChat has been installed') {
statusBarItem.text = `$(warning)DevChat`;
if (devchatStatus !== 'has statisfied the dependency' && devchatStatus !== `${ASSISTANT_NAME_EN} has been installed`) {
statusBarItem.text = `$(warning)${ASSISTANT_NAME_EN}`;
statusBarItem.tooltip = `${devchatStatus}`;
if (devchatStatus === 'Missing required dependency: Python3') {
@ -42,7 +41,7 @@ export function createStatusBarItem(context: vscode.ExtensionContext): vscode.St
return;
}
statusBarItem.text = `$(pass)DevChat`;
statusBarItem.text = `$(pass)${ASSISTANT_NAME_EN}`;
statusBarItem.tooltip = `ready to chat`;
statusBarItem.command = 'devcaht.onStatusBarClick';
progressBar.update(`Checking dependencies: Success`, 0);
@ -58,7 +57,7 @@ export function createStatusBarItem(context: vscode.ExtensionContext): vscode.St
clearInterval(timer);
} catch (error) {
statusBarItem.text = `$(warning)DevChat`;
statusBarItem.text = `$(warning)${ASSISTANT_NAME_EN}`;
statusBarItem.tooltip = `Error: ${error}`;
statusBarItem.command = undefined;
progressBar.endWithError(`Checking dependencies: Fail with exception.`);

View File

@ -1,14 +1,10 @@
import * as fs from 'fs';
import * as path from 'path';
import { logger } from "../util/logger";
import { UiUtilWrapper } from "../util/uiUtil";
import { ApiKeyManager } from '../util/apiKey';
import { installDevchat } from '../util/python_installer/install_devchat';
import { ASSISTANT_NAME_EN } from '../util/constants';
let devchatStatus = '';
let apiKeyStatus = '';
let preDevchatStatus = '';
@ -27,26 +23,31 @@ export async function dependencyCheck(): Promise<string> {
// define subfunction to check devchat dependency
const getDevChatStatus = async (): Promise<string> => {
const statuses = {
installing: `installing ${ASSISTANT_NAME_EN}`,
installed: `${ASSISTANT_NAME_EN} has been installed`,
error: `An error occurred during the installation of ${ASSISTANT_NAME_EN}`
}
if (devchatStatus === '') {
devchatStatus = 'installing devchat';
devchatStatus = statuses.installing;
const devchatCommandEnv = await installDevchat();
if (devchatCommandEnv) {
logger.channel()?.info(`Python: ${devchatCommandEnv}`);
devchatStatus = 'DevChat has been installed';
devchatStatus = statuses.installed;
return devchatStatus;
} else {
logger.channel()?.info(`Python: undefined`);
devchatStatus = 'An error occurred during the installation of DevChat';
devchatStatus = statuses.error;
return devchatStatus;
}
} else if (devchatStatus === 'has statisfied the dependency') {
return devchatStatus;
} else if (devchatStatus === 'installing devchat') {
} else if (devchatStatus === statuses.installing) {
return devchatStatus;
} else if (devchatStatus === 'DevChat has been installed') {
} else if (devchatStatus === statuses.installed) {
return devchatStatus;
} else if (devchatStatus === 'An error occurred during the installation of DevChat') {
} else if (devchatStatus === statuses.error) {
return devchatStatus;
}
return "";
@ -55,7 +56,7 @@ export async function dependencyCheck(): Promise<string> {
const devchatPackageStatus = await getDevChatStatus();
if (devchatPackageStatus !== preDevchatStatus) {
logger.channel()?.info(`devchat status: ${devchatPackageStatus}`);
logger.channel()?.info(`${ASSISTANT_NAME_EN} status: ${devchatPackageStatus}`);
preDevchatStatus = devchatPackageStatus;
}

9
src/util/constants.ts Normal file
View File

@ -0,0 +1,9 @@
import { ExtensionContextHolder } from "./extensionContext";
export let ASSISTANT_NAME_EN = "DevChat";
export let ASSISTANT_NAME_ZH = "DevChat";
export function updateNames(nameEN, nameZH) {
ASSISTANT_NAME_EN = nameEN;
ASSISTANT_NAME_ZH = nameZH;
}

View File

@ -1,3 +1,4 @@
import { ASSISTANT_NAME_ZH } from "./constants";
import { LogChannel } from "./logger";
import * as vscode from 'vscode';
@ -7,7 +8,7 @@ export class LoggerChannelVscode implements LogChannel {
private static _instance: LoggerChannelVscode;
private constructor() {
this._channel = vscode.window.createOutputChannel('DevChat', { log: true });
this._channel = vscode.window.createOutputChannel(ASSISTANT_NAME_ZH, { log: true });
}
public static getInstance(): LoggerChannelVscode {

View File

@ -1,5 +1,6 @@
import * as vscode from 'vscode';
import { ASSISTANT_NAME_ZH } from './constants';
export class ProgressBar {
private message: string;
@ -13,7 +14,7 @@ export class ProgressBar {
init() {
vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: 'DevChat',
title: ASSISTANT_NAME_ZH,
cancellable: false
}, (progress, token) => {
return new Promise<void>((resolve) => {