feat: update platform

This commit is contained in:
smallstone 2023-11-09 18:02:57 +08:00
parent 3ab349c6c4
commit 700cfff6ba
7 changed files with 9054 additions and 174 deletions

19
src/main.html Normal file
View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>DevChat</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="app"></div>
<script></script>
</body>
</html>

6
src/types/globle.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare global {
interface Window {
[key: string]: any;
}
}
export {};

View File

@ -1,12 +1,12 @@
// const vscodeApi = window.acquireVsCodeApi();
// @ts-ignore const vscodeApi = {
const vscodeApi = window.acquireVsCodeApi(); postMessage: (message: any) => {},
};
class MessageUtil { class MessageUtil {
private static instance: MessageUtil; private static instance: MessageUtil;
handlers: { [x: string]: any; }; handlers: { [x: string]: any };
messageListener: any; messageListener: any;
constructor() { constructor() {
@ -14,13 +14,13 @@ class MessageUtil {
this.messageListener = null; this.messageListener = null;
if (!this.messageListener) { if (!this.messageListener) {
this.messageListener = (event: { data: any; }) => { this.messageListener = (event: { data: any }) => {
const message = event.data; const message = event.data;
this.handleMessage(message); this.handleMessage(message);
}; };
window.addEventListener('message', this.messageListener); window.addEventListener("message", this.messageListener);
} else { } else {
console.log('Message listener has already been bound.'); console.log("Message listener has already been bound.");
} }
} }
@ -49,17 +49,22 @@ class MessageUtil {
} }
// Handle a received message // Handle a received message
handleMessage(message: { command: string | number; }) { handleMessage(message: { command: string | number }) {
const handlers = this.handlers[message.command]; const handlers = this.handlers[message.command];
if (handlers) { if (handlers) {
handlers.forEach((handler: (arg0: { command: string | number; }) => any) => handler(message)); handlers.forEach((handler: (arg0: { command: string | number }) => any) =>
handler(message)
);
} }
} }
// Send a message to the VSCode API // Send a message to the VSCode API
sendMessage(message: any) { sendMessage(message: any) {
// console.log(`${JSON.stringify(message)}`); if (process.env.platform === "idea") {
vscodeApi.postMessage(message); window.callJAVA();
} else {
window.acquireVsCodeApi().postMessage(message);
}
} }
} }

View File

@ -1,5 +1,13 @@
import {
import { Stack, Container, Divider, Box, Group,Text, Button, createStyles } from "@mantine/core"; Stack,
Container,
Divider,
Box,
Group,
Text,
Button,
createStyles,
} from "@mantine/core";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import MessageBody from "@/views/components/MessageBody"; import MessageBody from "@/views/components/MessageBody";
import MessageAvatar from "@/views/components/MessageAvatar"; import MessageAvatar from "@/views/components/MessageAvatar";
@ -8,96 +16,142 @@ import { useMst } from "@/views/stores/RootStore";
import { Message } from "@/views/stores/ChatStore"; import { Message } from "@/views/stores/ChatStore";
import MessageContext from "@/views/components/MessageContext"; import MessageContext from "@/views/components/MessageContext";
import CurrentMessage from "@/views/components/CurrentMessage"; import CurrentMessage from "@/views/components/CurrentMessage";
import { Card } from '@mantine/core'; import { Card } from "@mantine/core";
import { IconInfoSquareRounded } from "@tabler/icons-react"; import { IconInfoSquareRounded } from "@tabler/icons-react";
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
card:{ card: {
backgroundColor: 'var(--vscode-menu-background)', backgroundColor: "var(--vscode-menu-background)",
fontFamily: 'var(--vscode-editor-font-familyy)', fontFamily: "var(--vscode-editor-font-familyy)",
fontSize: 'var(--vscode-editor-font-size)', fontSize: "var(--vscode-editor-font-size)",
color: 'var(--vscode-menu-foreground)', color: "var(--vscode-menu-foreground)",
borderColor: 'var(--vscode-menu-border)', borderColor: "var(--vscode-menu-border)",
},
cardDescription: {
marginTop: 10,
marginBottom: 10,
},
button: {
backgroundColor: "#ED6A45",
fontFamily: "var(--vscode-editor-font-familyy)",
fontSize: "var(--vscode-editor-font-size)",
color: "#fff",
"&:hover": {
backgroundColor: "#ED6A45",
opacity: 0.8,
}, },
cardDescription:{ "&:focus": {
marginTop: 10, backgroundColor: "#ED6A45",
marginBottom: 10, opacity: 0.8,
}, },
button:{ },
backgroundColor:"#ED6A45", }));
fontFamily: 'var(--vscode-editor-font-familyy)',
fontSize: 'var(--vscode-editor-font-size)',
color:"#fff",
"&:hover":{
backgroundColor:"#ED6A45",
opacity: 0.8,
},
"&:focus":{
backgroundColor:"#ED6A45",
opacity: 0.8,
}
}
}));
const MessageList = observer((props: any) => { const MessageList = observer((props: any) => {
const { chat } = useMst(); const { chat } = useMst();
const {classes} = useStyles(); const { classes } = useStyles();
return (<Stack spacing={0} sx={{margin:'0 10px 10px 10px'}}> return (
{chat.messages.map((item, index: number) => { <Stack spacing={0} sx={{ margin: "0 10px 10px 10px" }}>
const { message: messageText, type: messageType, hash: messageHash, contexts, confirm } = item; {chat.messages.map((item, index: number) => {
// setMessage(messageText); const {
return <Stack message: messageText,
spacing={0} type: messageType,
key={`message-${index}`} hash: messageHash,
sx={{ contexts,
padding: 0, confirm,
margin: 0 } = item;
}}> // setMessage(messageText);
<MessageAvatar return (
key={`message-header-${index}`} <Stack
showDelete={index === chat.messages.length - 2} spacing={0}
deleteHash={messageHash} key={`message-${index}`}
avatarType={messageType} sx={{
copyMessage={messageText} padding: 0,
messageContexts={contexts} /> margin: 0,
<Box }}
key={`message-container-${index}`} >
sx={{ <MessageAvatar
margin: 0, key={`message-header-${index}`}
padding: 0, showDelete={index === chat.messages.length - 2}
pre: { deleteHash={messageHash}
whiteSpace: 'break-spaces' avatarType={messageType}
}, copyMessage={messageText}
}}> messageContexts={contexts}
{ messageType === 'bot' && confirm && <Card shadow="sm" padding="xs" radius="md" withBorder className={classes.card}> />
<Card.Section withBorder inheritPadding py="xs"> <Box
<Group position="left"> key={`message-container-${index}`}
<IconInfoSquareRounded size={20} /> sx={{
<Text fw={500}>GPT-4 Usage Required</Text> margin: 0,
</Group> padding: 0,
</Card.Section> pre: {
<Text className={classes.cardDescription}> whiteSpace: "break-spaces",
DevChat will make GPT-4 API calls to analyze up to ten source files, costing <strong>approximately $0.4 USD per question</strong>. },
<br/> }}
<br/> >
Would you like to proceed? {messageType === "bot" && confirm && (
</Text> <Card
<Group position="right" > shadow="sm"
<Button size="compact-xs" className={classes.button} onClick={()=> chat.sendLastUserMessage() }>Yes</Button> padding="xs"
<Button size="compact-xs" className={classes.button} onClick={()=> chat.cancelDevchatAsk()}>No</Button> radius="md"
</Group> withBorder
</Card>} className={classes.card}
<MessageContext key={`message-context-${index}`} contexts={contexts} /> >
<MessageBody key={`message-codeblock-${index}`} messageType={messageType} messageDone={!(index === chat.messages.length -1 && chat.generating)}> <Card.Section withBorder inheritPadding py="xs">
{messageText} <Group position="left">
</MessageBody> <IconInfoSquareRounded size={20} />
</Box > <Text fw={500}>GPT-4 Usage Required</Text>
{index !== chat.messages.length - 1 && <Divider my={3} key={`message-divider-${index}`} />} </Group>
</Stack >; </Card.Section>
})} <Text className={classes.cardDescription}>
<CurrentMessage /> DevChat will make GPT-4 API calls to analyze up to ten
</Stack>); source files, costing{" "}
<strong>approximately $0.4 USD per question</strong>.
<br />
<br />
Would you like to proceed?
</Text>
<Group position="right">
<Button
size="compact-xs"
className={classes.button}
onClick={() => chat.sendLastUserMessage()}
>
Yes
</Button>
<Button
size="compact-xs"
className={classes.button}
onClick={() => chat.cancelDevchatAsk()}
>
No
</Button>
</Group>
</Card>
)}
<MessageContext
key={`message-context-${index}`}
contexts={contexts}
/>
<MessageBody
key={`message-codeblock-${index}`}
messageType={messageType}
messageDone={
!(index === chat.messages.length - 1 && chat.generating)
}
>
{messageText}
</MessageBody>
</Box>
{index !== chat.messages.length - 1 && (
<Divider my={3} key={`message-divider-${index}`} />
)}
</Stack>
);
})}
<CurrentMessage />
</Stack>
);
}); });
export default MessageList; export default MessageList;

View File

@ -1,36 +1,36 @@
//@ts-check //@ts-check
'use strict'; "use strict";
const path = require('path'); const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require("html-webpack-plugin");
const { DefinePlugin } = require('webpack'); const { DefinePlugin } = require("webpack");
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require("copy-webpack-plugin");
//@ts-check //@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/ /** @typedef {import('webpack').Configuration} WebpackConfig **/
/** @type WebpackConfig */ /** @type WebpackConfig */
const extensionConfig = { const extensionConfig = {
name: 'vscode extension', name: "vscode extension",
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ target: "node", // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ entry: "./src/extension.ts", // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
output: { output: {
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, "dist"),
filename: 'extension.js', filename: "extension.js",
libraryTarget: 'commonjs2' libraryTarget: "commonjs2",
}, },
externals: { externals: {
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
// modules added here also need to be added in the .vscodeignore file // modules added here also need to be added in the .vscodeignore file
}, },
resolve: { resolve: {
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
extensions: ['.ts', '.json'] extensions: [".ts", ".json"],
}, },
module: { module: {
rules: [ rules: [
@ -39,45 +39,45 @@ const extensionConfig = {
exclude: /node_modules/, exclude: /node_modules/,
use: [ use: [
{ {
loader: 'babel-loader', loader: "babel-loader",
options: { options: {
presets: [ presets: [
'@babel/preset-env', "@babel/preset-env",
'@babel/preset-react', "@babel/preset-react",
'@babel/preset-typescript' "@babel/preset-typescript",
] ],
} },
}, },
{ {
loader: 'ts-loader' loader: "ts-loader",
} },
] ],
}, },
] ],
}, },
devtool: 'nosources-source-map', devtool: "nosources-source-map",
infrastructureLogging: { infrastructureLogging: {
level: "log", // enables logging required for problem matchers level: "log", // enables logging required for problem matchers
}, },
plugins: [] plugins: [],
}; };
/** @type WebpackConfig */ /** @type WebpackConfig */
const webviewConfig = { const webviewConfig = {
name: 'webview', name: "webview",
target: 'web', target: "web",
mode: 'development', mode: "development",
entry: './src/index.tsx', entry: "./src/index.tsx",
output: { output: {
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, "dist"),
filename: 'index.js', filename: "index.js",
publicPath: "/",
}, },
resolve: { resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'], extensions: [".ts", ".tsx", ".js", ".json"],
alias: { alias: {
'@': path.resolve(__dirname, 'src/') "@": path.resolve(__dirname, "src/"),
}, },
}, },
module: { module: {
@ -87,89 +87,85 @@ const webviewConfig = {
exclude: /node_modules/, exclude: /node_modules/,
use: [ use: [
{ {
loader: 'babel-loader', loader: "babel-loader",
options: { options: {
presets: [ presets: [
'@babel/preset-env', "@babel/preset-env",
'@babel/preset-react', "@babel/preset-react",
'@babel/preset-typescript' "@babel/preset-typescript",
] ],
} },
}, },
{ {
loader: 'ts-loader' loader: "ts-loader",
} },
] ],
}, },
{ {
test: /\.jsx?$/, test: /\.jsx?$/,
exclude: /node_modules/, exclude: /node_modules/,
use: [{ use: [
loader: 'babel-loader', {
options: { loader: "babel-loader",
presets: [ options: {
[ presets: [["@babel/preset-env", "@babel/preset-react"]],
'@babel/preset-env', },
'@babel/preset-react',
],
]
}, },
}] ],
}, },
{ {
test: /\.css$/i, test: /\.css$/i,
use: [ use: [
{ {
loader: 'style-loader', loader: "style-loader",
}, },
{ {
loader: 'css-loader', loader: "css-loader",
options: { options: {
modules: { modules: {
localIdentName: '[name]__[local]___[hash:base64:5]' localIdentName: "[name]__[local]___[hash:base64:5]",
} },
} },
} },
], ],
include: /views/ include: /views/,
}, },
{ {
test: /\.json$/i, test: /\.json$/i,
use: 'json-loader', use: "json-loader",
type: 'asset/source' type: "asset/source",
}, },
{ {
test: /\.(png|jpg|jpeg|gif|svg)$/, // 匹配文件类型 test: /\.(png|jpg|jpeg|gif|svg)$/, // 匹配文件类型
use: [ use: [
{ {
loader: 'file-loader', // 使用file-loader loader: "file-loader", // 使用file-loader
options: { options: {
name: '[name].[ext]', // 输出文件的名称和扩展名 name: "[name].[ext]", // 输出文件的名称和扩展名
outputPath: 'assets/', // 输出文件的路径 outputPath: "assets/", // 输出文件的路径
}, },
}, },
], ],
} },
] ],
}, },
devtool: 'source-map', devtool: "source-map",
infrastructureLogging: { infrastructureLogging: {
level: "log", level: "log",
}, },
plugins: [ plugins: [
// generate an HTML file that includes the extension's JavaScript file // generate an HTML file that includes the extension's JavaScript file
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src', 'index.html'), template: path.resolve(__dirname, "src", "index.html"),
filename: 'index.html', filename: "index.html",
chunks: ['index'] chunks: ["index"],
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src', 'welcome.html'), template: path.resolve(__dirname, "src", "welcome.html"),
filename: 'welcome.html', filename: "welcome.html",
chunks: ['welcome'] chunks: ["welcome"],
}), }),
] ],
}; };
module.exports = [extensionConfig, webviewConfig]; module.exports = [extensionConfig, webviewConfig];

105
webpack.idea.config.js Normal file
View File

@ -0,0 +1,105 @@
//@ts-check
"use strict";
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const webpack = require("webpack");
const webviewConfig = {
name: "webview",
target: "web",
mode: "production",
entry: "./src/index.tsx",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
publicPath: "/",
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"],
alias: {
"@": path.resolve(__dirname, "src/"),
},
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript",
],
},
},
{
loader: "ts-loader",
},
],
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", "@babel/preset-react"]],
},
},
],
},
{
test: /\.css$/i,
use: [
{
loader: "style-loader",
},
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[name]__[local]___[hash:base64:5]",
},
},
},
],
include: /views/,
},
{
test: /\.json$/i,
use: "json-loader",
type: "asset/source",
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/, // 匹配文件类型
type: "asset/inline",
},
],
},
devtool: false,
infrastructureLogging: {
level: "log",
},
plugins: [
// generate an HTML file that includes the extension's JavaScript file
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "main.html"),
filename: "main.html",
chunks: ["main"],
}),
new CleanWebpackPlugin(),
new webpack.ProgressPlugin(),
new webpack.DefinePlugin({
"process.env.platform": "idea",
}),
],
};
module.exports = webviewConfig;

8695
yarn.lock Normal file

File diff suppressed because it is too large Load Diff