Merge pull request #587 from devchat-ai/parameterize-packaging

Parameterize packaging
This commit is contained in:
Tim 2024-08-27 17:27:05 +08:00 committed by GitHub
commit f6227ce1c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 153 additions and 150 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"
}
]
}

2
gui

@ -1 +1 @@
Subproject commit e7dea52c58d9da9dfb47c10dc20d8c35e9fd9837
Subproject commit d3ae07dc82798ba0679629ddf4feb79339458e6d

View File

@ -1,13 +1,17 @@
{
"name": "devchat",
"displayName": "DevChat",
"name": "${EXTENSION_NAME}",
"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"
}
],
@ -344,10 +348,14 @@
"vscode:uninstall": "node ./dist/uninstall",
"vscode:prepublish": "npm run package",
"compile": "webpack",
"watch": "webpack --watch",
"watch": "node prebuild.js && webpack --watch",
"prebuild": "node prebuild.js",
"postbuild": "git checkout -- assets package.json",
"prepackage": "node prebuild.js",
"postpackage": "git checkout -- assets package.json",
"package": "webpack --mode production --devtool hidden-source-map",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"watch-tests": "npm run prebuild && tsc -p . -w --outDir out",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"lint": "eslint src --ext ts",
"test": "mocha",

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) => {