commit
1847e100d2
911
package-lock.json
generated
911
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -174,6 +174,7 @@
|
||||
"nonce": "^1.0.4",
|
||||
"openai": "^3.2.1",
|
||||
"quote": "^0.4.0",
|
||||
"react-remark": "^2.1.0",
|
||||
"shell-escape": "^0.2.0",
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
|
45
src/utils/MessageUtil.ts
Normal file
45
src/utils/MessageUtil.ts
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
// @ts-ignore
|
||||
const vscodeApi = window.acquireVsCodeApi();
|
||||
|
||||
class MessageUtil {
|
||||
handlers: { [x: string]: any; };
|
||||
constructor() {
|
||||
this.handlers = {};
|
||||
}
|
||||
|
||||
// Register a message handler for a specific message type
|
||||
registerHandler(messageType: string, handler: { (message: { text: string; }): void; (message: { text: string; }): void; }) {
|
||||
if (!this.handlers[messageType]) {
|
||||
this.handlers[messageType] = [];
|
||||
}
|
||||
this.handlers[messageType].push(handler);
|
||||
}
|
||||
|
||||
// Unregister a message handler for a specific message type
|
||||
unregisterHandler(messageType: string | number, handler: any) {
|
||||
if (this.handlers[messageType]) {
|
||||
this.handlers[messageType] = this.handlers[messageType].filter(
|
||||
(h: any) => h !== handler
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle a received message
|
||||
handleMessage(message: { command: string | number; }) {
|
||||
console.log("handleMessage", message);
|
||||
const handlers = this.handlers[message.command];
|
||||
if (handlers) {
|
||||
handlers.forEach((handler: (arg0: { command: string | number; }) => any) => handler(message));
|
||||
}
|
||||
}
|
||||
|
||||
// Send a message to the VSCode API
|
||||
sendMessage(message: { command: string; text: string; }) {
|
||||
console.log("sendMessage", message);
|
||||
vscodeApi.postMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Export the MessageUtil class as a module
|
||||
export default MessageUtil;
|
@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { Container } from '@mantine/core';
|
||||
import { Avatar, Container, Divider, Flex, Grid, Stack, TypographyStylesProvider } from '@mantine/core';
|
||||
import { Input, Tooltip } from '@mantine/core';
|
||||
import { List } from '@mantine/core';
|
||||
import { ScrollArea } from '@mantine/core';
|
||||
@ -8,8 +8,11 @@ import { createStyles } from '@mantine/core';
|
||||
import { ActionIcon } from '@mantine/core';
|
||||
import { Menu, Button, Text } from '@mantine/core';
|
||||
import { useViewportSize } from '@mantine/hooks';
|
||||
import { IconSend, IconSquareRoundedPlus } from '@tabler/icons-react';
|
||||
import { IconEdit, IconRobot, IconSend, IconSquareRoundedPlus, IconUser } from '@tabler/icons-react';
|
||||
import { IconSettings, IconSearch, IconPhoto, IconMessageCircle, IconTrash, IconArrowsLeftRight } from '@tabler/icons-react';
|
||||
import { Prism } from '@mantine/prism';
|
||||
import { useRemark } from 'react-remark';
|
||||
import MessageUtil from '../utils/MessageUtil';
|
||||
|
||||
const useStyles = createStyles((theme, _params, classNames) => ({
|
||||
panel: {
|
||||
@ -34,17 +37,40 @@ const useStyles = createStyles((theme, _params, classNames) => ({
|
||||
fontSize: '0.8rem',
|
||||
color: theme.colors.gray[6],
|
||||
},
|
||||
responseContent: {
|
||||
marginTop: 8,
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
},
|
||||
icon: {
|
||||
pointerEvents: 'all',
|
||||
},
|
||||
avatar: {
|
||||
marginTop: 8,
|
||||
marginLeft: 8,
|
||||
},
|
||||
messageBody: {
|
||||
},
|
||||
}));
|
||||
|
||||
const chatPanel = () => {
|
||||
|
||||
const [reactContent, setMarkdownSource] = useRemark();
|
||||
const [opened, setOpened] = useState(false);
|
||||
const [input, setInput] = useState('');
|
||||
const [commandOpened, setCommandOpened] = useState(false);
|
||||
const { classes } = useStyles();
|
||||
const { height, width } = useViewportSize();
|
||||
const messageUtil = new MessageUtil();
|
||||
|
||||
const demoCode = `import { Button } from '@mantine/core';
|
||||
function Demo() {
|
||||
return <Button>Hello</Button>
|
||||
}`;
|
||||
|
||||
setMarkdownSource(`# code block
|
||||
print '3 backticks or'
|
||||
print 'indent 4 spaces'`);
|
||||
|
||||
const handlePlusBottonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setOpened(!opened);
|
||||
@ -53,26 +79,89 @@ const chatPanel = () => {
|
||||
const handleContainerClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (opened) { setOpened(false); }
|
||||
};
|
||||
const handleSendClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
const message = input;
|
||||
if (message) {
|
||||
// Add the user's message to the chat UI
|
||||
// addMessageToUI('user', message);
|
||||
|
||||
// Clear the input field
|
||||
event.currentTarget.value = '';
|
||||
|
||||
// Process and send the message to the extension
|
||||
messageUtil.sendMessage({
|
||||
command: 'sendMessage',
|
||||
text: message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Register message handlers for receiving messages from the extension
|
||||
messageUtil.registerHandler('receiveMessage', (message: { text: string; }) => {
|
||||
console.log(`receiveMessage: ${message.text}`);
|
||||
// Add the received message to the chat UI as a bot message
|
||||
setMarkdownSource(message.text);
|
||||
});
|
||||
|
||||
messageUtil.registerHandler('receiveMessagePartial', (message: { text: string; }) => {
|
||||
console.log(`receiveMessagePartial: ${message.text}`);
|
||||
// Add the received message to the chat UI as a bot message
|
||||
setMarkdownSource(message.text);
|
||||
});
|
||||
|
||||
|
||||
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value
|
||||
const value = event.target.value;
|
||||
// if value start with '/' command show menu
|
||||
if (value.startsWith('/')) {
|
||||
setCommandOpened(true);
|
||||
} else {
|
||||
setCommandOpened(false);
|
||||
}
|
||||
}
|
||||
setInput(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container className={classes.panel} onClick={handleContainerClick}>
|
||||
<ScrollArea h={height - 70} type="never">
|
||||
<List>
|
||||
<List.Item>Clone or download repository from GitHub</List.Item>
|
||||
<List.Item>Install dependencies with yarn</List.Item>
|
||||
<List.Item>To start development server run npm start command</List.Item>
|
||||
<List.Item>Run tests to make sure your changes do not break the build</List.Item>
|
||||
<List.Item>Submit a pull request once you are done</List.Item>
|
||||
</List>
|
||||
<Flex
|
||||
mih={50}
|
||||
gap="md"
|
||||
justify="flex-start"
|
||||
align="flex-start"
|
||||
direction="row"
|
||||
wrap="wrap"
|
||||
className={classes.messageBody}
|
||||
>
|
||||
<Avatar color="indigo" size='md' radius="xl" className={classes.avatar}>
|
||||
<IconUser size="1.5rem" />
|
||||
</Avatar>
|
||||
<Container className={classes.responseContent}>
|
||||
<Text>
|
||||
Write a hello world, and explain it.
|
||||
</Text>
|
||||
</Container>
|
||||
{/* <ActionIcon>
|
||||
<IconEdit size="1.5rem" />
|
||||
</ActionIcon> */}
|
||||
</Flex>
|
||||
<Divider my="sm" label="Mar 4, 2023" labelPosition="center" />
|
||||
<Flex
|
||||
mih={50}
|
||||
gap="md"
|
||||
justify="flex-start"
|
||||
align="flex-start"
|
||||
direction="row"
|
||||
wrap="wrap"
|
||||
className={classes.messageBody}
|
||||
>
|
||||
<Avatar color="blue" size='md' radius="xl" className={classes.avatar}>
|
||||
<IconRobot size="1.5rem" />
|
||||
</Avatar>
|
||||
<Container className={classes.responseContent}>
|
||||
{reactContent}
|
||||
</Container>
|
||||
</Flex>
|
||||
</ScrollArea>
|
||||
<Menu id='plusMenu' shadow="md" width={200} opened={opened} onChange={setOpened} >
|
||||
<Menu.Dropdown className={classes.plusMenu}>
|
||||
@ -154,7 +243,7 @@ const chatPanel = () => {
|
||||
</ActionIcon>
|
||||
}
|
||||
rightSection={
|
||||
<ActionIcon>
|
||||
<ActionIcon onClick={handleSendClick}>
|
||||
<IconSend size="1rem" />
|
||||
</ActionIcon>
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(
|
||||
const container = document.getElementById('app')!;
|
||||
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
||||
root.render(
|
||||
<MantineProvider withGlobalStyles withNormalizeCSS>
|
||||
<App />
|
||||
</MantineProvider>,
|
||||
document.getElementById('app'));
|
||||
</MantineProvider>
|
||||
);
|
||||
|
@ -12,17 +12,16 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
|
||||
/** @type WebpackConfig */
|
||||
const extensionConfig = {
|
||||
name: 'vscode extension',
|
||||
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')
|
||||
|
||||
entry: {
|
||||
extension: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
index: './src/views/index.tsx'
|
||||
},
|
||||
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
filename: 'extension.js',
|
||||
libraryTarget: 'commonjs2'
|
||||
},
|
||||
externals: {
|
||||
@ -31,6 +30,51 @@ const extensionConfig = {
|
||||
},
|
||||
resolve: {
|
||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||
extensions: ['.ts', '.json']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'ts-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
devtool: 'nosources-source-map',
|
||||
infrastructureLogging: {
|
||||
level: "log", // enables logging required for problem matchers
|
||||
},
|
||||
plugins: []
|
||||
};
|
||||
|
||||
|
||||
/** @type WebpackConfig */
|
||||
const webviewConfig = {
|
||||
name: 'webview',
|
||||
target: 'web',
|
||||
mode: 'development',
|
||||
|
||||
entry: './src/views/index.tsx',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.json']
|
||||
},
|
||||
module: {
|
||||
@ -56,8 +100,18 @@ const extensionConfig = {
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
use: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
use: [{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
],
|
||||
]
|
||||
},
|
||||
}]
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
@ -94,9 +148,9 @@ const extensionConfig = {
|
||||
}
|
||||
]
|
||||
},
|
||||
devtool: 'nosources-source-map',
|
||||
devtool: 'source-map',
|
||||
infrastructureLogging: {
|
||||
level: "log", // enables logging required for problem matchers
|
||||
level: "log",
|
||||
},
|
||||
plugins: [
|
||||
// generate an HTML file that includes the extension's JavaScript file
|
||||
@ -109,12 +163,9 @@ const extensionConfig = {
|
||||
patterns: [
|
||||
{ from: 'assets', to: 'assets' },
|
||||
],
|
||||
}),
|
||||
// define global variables
|
||||
new DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('development')
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
module.exports = [extensionConfig];
|
||||
|
||||
module.exports = [extensionConfig, webviewConfig];
|
||||
|
Loading…
x
Reference in New Issue
Block a user