commit
29c571c3c2
43
package-lock.json
generated
43
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "devchat",
|
||||
"version": "0.1.33",
|
||||
"version": "0.1.55",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "devchat",
|
||||
"version": "0.1.33",
|
||||
"version": "0.1.55",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.8",
|
||||
"@mantine/core": "^6.0.10",
|
||||
@ -40,7 +40,6 @@
|
||||
"unified": "^11.0.3",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"uuid": "^9.0.0",
|
||||
"xmlrpc": "^1.3.2",
|
||||
"yaml": "^2.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -90,8 +89,7 @@
|
||||
"vscode-test": "^1.6.1",
|
||||
"webpack": "^5.76.3",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.13.3",
|
||||
"xmlrpc": "^1.3.2"
|
||||
"webpack-dev-server": "^4.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.75.0"
|
||||
@ -13004,12 +13002,6 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
@ -15007,29 +14999,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
|
||||
"integrity": "sha512-eKRAFz04jghooy8muekqzo8uCSVNeyRedbuJrp0fovbLIi7wlsYtdUn3vBAAPq2Y3/0xMz2WMEUQ8yhVVO9Stw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlrpc": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlrpc/-/xmlrpc-1.3.2.tgz",
|
||||
"integrity": "sha512-jQf5gbrP6wvzN71fgkcPPkF4bF/Wyovd7Xdff8d6/ihxYmgETQYSuTc+Hl+tsh/jmgPLro/Aro48LMFlIyEKKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sax": "1.2.x",
|
||||
"xmlbuilder": "8.2.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8",
|
||||
"npm": ">=1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
@ -24529,12 +24498,6 @@
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"dev": true
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
|
@ -1,13 +1,34 @@
|
||||
import * as React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import { MantineProvider, MantineThemeOverride } from '@mantine/core';
|
||||
import { Provider, rootStore } from '@/views/stores/RootStore';
|
||||
import App from '@/views/App';
|
||||
|
||||
const container = document.getElementById('app')!;
|
||||
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
||||
const myTheme: MantineThemeOverride = {
|
||||
fontFamily: 'var(--vscode-editor-font-family)',
|
||||
colors: {
|
||||
"merico":[
|
||||
"#F9F5F4",
|
||||
"#EADAD6",
|
||||
"#E1C0B6",
|
||||
"#DEA594",
|
||||
"#E1886F",
|
||||
"#ED6A45",
|
||||
"#D75E3C",
|
||||
"#BD573B",
|
||||
"#9F5541",
|
||||
"#865143",
|
||||
],
|
||||
},
|
||||
primaryColor: 'merico',
|
||||
};
|
||||
|
||||
|
||||
root.render(
|
||||
<MantineProvider withGlobalStyles withNormalizeCSS>
|
||||
<MantineProvider withGlobalStyles withNormalizeCSS withCSSVariables
|
||||
theme={myTheme}>
|
||||
<Provider value={rootStore}>
|
||||
<App />
|
||||
</Provider>
|
||||
|
@ -100,9 +100,11 @@ export interface CommandResult {
|
||||
|
||||
export class CommandRun {
|
||||
private childProcess: any;
|
||||
private _input: string;
|
||||
|
||||
// init childProcess in construction function
|
||||
constructor() {
|
||||
this._input = "";
|
||||
this.childProcess = null;
|
||||
}
|
||||
|
||||
@ -129,7 +131,8 @@ export class CommandRun {
|
||||
let stderr = '';
|
||||
|
||||
this.childProcess.stdout.on('data', (data: { toString: () => any; }) => {
|
||||
const dataStr = data.toString();
|
||||
const dataStr = this._input + data.toString();
|
||||
this._input = "";
|
||||
if (onData) {
|
||||
onData(dataStr);
|
||||
}
|
||||
@ -186,6 +189,7 @@ export class CommandRun {
|
||||
|
||||
public write(input: string) {
|
||||
if (this.childProcess) {
|
||||
this._input += input;
|
||||
this.childProcess.stdin.write(input);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export default function App() {
|
||||
styles={{
|
||||
main: {
|
||||
padding:'40px 0 0 0',
|
||||
fontFamily: 'var(--vscode-editor-font-familyy)',
|
||||
fontFamily: 'var(--vscode-editor-font-family)',
|
||||
fontSize: 'var(--vscode-editor-font-size)',
|
||||
},
|
||||
}}
|
||||
|
286
src/views/components/ChatMark/index.tsx
Normal file
286
src/views/components/ChatMark/index.tsx
Normal file
@ -0,0 +1,286 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Box, Button, Checkbox, Text, Radio, Textarea, createStyles } from '@mantine/core';
|
||||
import { useListState, useSetState } from '@mantine/hooks';
|
||||
import { useMst } from '@/views/stores/RootStore';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
container:{
|
||||
padding:0,
|
||||
margin:0,
|
||||
},
|
||||
submit:{
|
||||
marginTop:theme.spacing.xs,
|
||||
marginRight:theme.spacing.xs,
|
||||
marginBottom:theme.spacing.xs,
|
||||
},
|
||||
cancel:{
|
||||
},
|
||||
button:{
|
||||
marginTop:theme.spacing.xs,
|
||||
marginRight:theme.spacing.xs,
|
||||
marginBottom:theme.spacing.xs,
|
||||
},
|
||||
checkbox:{
|
||||
marginTop:theme.spacing.xs,
|
||||
marginBottom:theme.spacing.xs,
|
||||
},
|
||||
label:{
|
||||
color:'var(--vscode-editor-foreground)',
|
||||
},
|
||||
radio:{
|
||||
marginTop:theme.spacing.xs,
|
||||
marginBottom:theme.spacing.xs,
|
||||
},
|
||||
editor:{
|
||||
backgroundColor: 'var(--vscode-input-background)',
|
||||
borderColor: 'var(--vscode-input-border)',
|
||||
color: 'var(--vscode-input-foreground)',
|
||||
},
|
||||
editorWrapper:{
|
||||
marginTop:theme.spacing.xs,
|
||||
marginBottom:theme.spacing.xs,
|
||||
}
|
||||
}));
|
||||
|
||||
interface Wdiget{
|
||||
id:string,
|
||||
value:string,
|
||||
title?:string,
|
||||
type:'editor'|'checkbox'|'radio'|'button'|'text'
|
||||
}
|
||||
|
||||
const ChatMark = ({ children,value }) => {
|
||||
const {classes} = useStyles();
|
||||
const [widgets,widgetsHandlers] = useListState<Wdiget>();
|
||||
const {chat} = useMst();
|
||||
const [autoForm,setAutoForm] = useState(false); // if any widget is checkbox,radio or editor wdiget, the form is auto around them
|
||||
const values = value?yaml.load(value):{};
|
||||
const [disabled,setDisabled] = useState(!!value);
|
||||
|
||||
const handleSubmit = () => {
|
||||
let formData = {};
|
||||
widgets.forEach((widget)=>{
|
||||
if(widget.type === 'text'
|
||||
|| widget.type === 'button'
|
||||
|| (widget.type === 'radio' && widget.value === 'unchecked')
|
||||
|| (widget.type === 'checkbox' && widget.value === 'unchecked')){
|
||||
// ignore
|
||||
return;
|
||||
}
|
||||
formData[widget.id] = widget.value;
|
||||
});
|
||||
chat.userInput(formData);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
chat.userInput({
|
||||
'form':'canceled'
|
||||
});
|
||||
};
|
||||
|
||||
const handleButtonClick = ({event,index}) => {
|
||||
const widget = widgets[index];
|
||||
widget['value'] = event.currentTarget.value;;
|
||||
widgetsHandlers.setItem(index,widget);
|
||||
chat.userInput({
|
||||
[widget['id']]:'clicked'
|
||||
});
|
||||
};
|
||||
|
||||
const handleCheckboxChange = ({event,index})=>{
|
||||
const widget = widgets[index];
|
||||
widget['value'] = event.currentTarget.checked?'checked':'unchecked';
|
||||
widgetsHandlers.setItem(index,widget);
|
||||
};
|
||||
const handleRadioChange = ({event,allValues})=>{
|
||||
widgetsHandlers.apply((item, index) => {
|
||||
if(allValues.includes(item.id)){
|
||||
if(item.id === event){
|
||||
item.value = 'checked';
|
||||
}else{
|
||||
item.value = 'unchecked';
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
const handleEditorChange = ({event,index})=>{
|
||||
const widget = widgets[index];
|
||||
widget['value'] = event.currentTarget.value;
|
||||
widgetsHandlers.setItem(index,widget);
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
|
||||
const lines = children.split('\n');
|
||||
let detectEditorId = '';
|
||||
let editorContentRecorder = '';
|
||||
|
||||
const textRegex = /^([^>].*)/; // Text widget
|
||||
const buttonRegex = /^>\s*\((.*?)\)\s*(.*)/; // Button widget
|
||||
const checkboxRegex = /^>\s*\[([x ]*)\]\((.*?)\)\s*(.*)/; // Checkbox widget
|
||||
const radioRegex = /^>\s*-\s*\((.*?)\)\s*(.*)/; // Radio button widget
|
||||
const editorRegex = /^>\s*\|\s*\((.*?)\)/; // Editor widget
|
||||
const editorContentRegex = /^>\s*(.*)/; // Editor widget
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
|
||||
let match;
|
||||
|
||||
if (match = line.match(textRegex)) {
|
||||
widgetsHandlers.append({
|
||||
id:`text${index}`,
|
||||
type:'text',
|
||||
value:line,
|
||||
});
|
||||
} else if (match = line.match(buttonRegex)) {
|
||||
const [id, title] = match.slice(1);
|
||||
widgetsHandlers.append({
|
||||
id,
|
||||
title,
|
||||
type:'button',
|
||||
value:title,
|
||||
});
|
||||
} else if (match = line.match(checkboxRegex)) {
|
||||
const [status, id, title] = match.slice(1);
|
||||
widgetsHandlers.append({
|
||||
id,
|
||||
title,
|
||||
type:'checkbox',
|
||||
value: disabled?'unchecked':status === 'x'?'checked':'unchecked',
|
||||
});
|
||||
setAutoForm(true);
|
||||
} else if (match = line.match(radioRegex)) {
|
||||
const [id, title] = match.slice(1);
|
||||
widgetsHandlers.append({
|
||||
id,
|
||||
title,
|
||||
type:'radio',
|
||||
value:'unchecked',
|
||||
});
|
||||
setAutoForm(true);
|
||||
} else if (match = line.match(editorRegex)) {
|
||||
const [id] = match.slice(1);
|
||||
detectEditorId = id;
|
||||
widgetsHandlers.append({
|
||||
id,
|
||||
type:'editor',
|
||||
value: '',
|
||||
});
|
||||
setAutoForm(true);
|
||||
} else if(match = line.match(editorContentRegex)){
|
||||
const [content] = match.slice(1);
|
||||
editorContentRecorder += content + '\n';
|
||||
}
|
||||
// if next line is not editor, then end current editor
|
||||
const nextLine = index + 1 < lines.length? lines[index + 1]:null;
|
||||
if (detectEditorId && (!nextLine || !nextLine.startsWith('>'))) {
|
||||
// remove last \n
|
||||
editorContentRecorder = editorContentRecorder.substring(0, editorContentRecorder.length - 1);
|
||||
// apply editor content to widget
|
||||
((editorId,editorContent) => widgetsHandlers.apply((item)=>{
|
||||
if(item.id === editorId && !disabled){
|
||||
item.value = editorContent;
|
||||
}
|
||||
return item;
|
||||
}))(detectEditorId,editorContentRecorder);
|
||||
// reset editor
|
||||
detectEditorId = '';
|
||||
editorContentRecorder = '';
|
||||
}
|
||||
});
|
||||
for (const key in values) {
|
||||
widgetsHandlers.apply((item)=>{
|
||||
if(item.id === key){
|
||||
item.value = values[key];
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
},[]);
|
||||
|
||||
// Render markdown widgets
|
||||
const renderWidgets = (widgets) => {
|
||||
let radioGroupTemp:any = [];
|
||||
let radioValuesTemp:any = [];
|
||||
let wdigetsTemp:any = [];
|
||||
widgets.map((widget, index) => {
|
||||
if (widget.type === 'text') {
|
||||
wdigetsTemp.push(<Text key={index}>{widget.value}</Text>);
|
||||
} else if (widget.type === 'button') {
|
||||
wdigetsTemp.push(<Button
|
||||
className={classes.button}
|
||||
disabled={disabled}
|
||||
key={'widget'+index}
|
||||
size='xs'
|
||||
value={widget.value}
|
||||
onClick={event => handleButtonClick({event,index})}>
|
||||
{widget.title}
|
||||
</Button>);
|
||||
} else if (widget.type === 'checkbox') {
|
||||
wdigetsTemp.push(<Checkbox
|
||||
classNames={{root:classes.checkbox,label:classes.label}}
|
||||
disabled={disabled}
|
||||
key={'widget'+index}
|
||||
label={widget.title}
|
||||
checked={widget.value==='checked'}
|
||||
size='xs'
|
||||
onChange={event => handleCheckboxChange({event,index})}/>);
|
||||
} else if (widget.type === 'radio') {
|
||||
radioValuesTemp.push(widget.id);
|
||||
radioGroupTemp.push(<Radio
|
||||
classNames={{root:classes.radio,label:classes.label}}
|
||||
disabled={disabled}
|
||||
key={'widget'+index}
|
||||
label={widget.title}
|
||||
value={widget.id}
|
||||
size='xs' />);
|
||||
// if next widget is not radio, then end current group
|
||||
const nextWidget = index + 1 < widgets.length? widgets[index + 1]:null;
|
||||
if (!nextWidget || nextWidget.type !== 'radio') {
|
||||
const radioGroup = ((radios,allValues)=><Radio.Group
|
||||
key={`radio-group-${index}`}
|
||||
onChange={
|
||||
event => handleRadioChange({
|
||||
event,
|
||||
allValues
|
||||
})
|
||||
}>
|
||||
{radios}
|
||||
</Radio.Group>)(radioGroupTemp,radioValuesTemp);
|
||||
radioGroupTemp = [];
|
||||
radioValuesTemp = [];
|
||||
wdigetsTemp.push(radioGroup);
|
||||
}
|
||||
} else if (widget.type === 'editor') {
|
||||
wdigetsTemp.push(<Textarea
|
||||
disabled={disabled}
|
||||
autosize
|
||||
classNames={{wrapper:classes.editorWrapper,input:classes.editor}}
|
||||
key={'widget'+index}
|
||||
defaultValue={widget.value}
|
||||
maxRows={10}
|
||||
onChange={event => handleEditorChange({event,index})}/>);
|
||||
}
|
||||
});
|
||||
return wdigetsTemp;
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={classes.container}>
|
||||
{autoForm && !disabled
|
||||
?<form>
|
||||
{renderWidgets(widgets)}
|
||||
<Box>
|
||||
<Button className={classes.submit} size='xs' onClick={handleSubmit}>Submit</Button>
|
||||
<Button className={classes.cancel} size='xs' onClick={handleCancel}>Cancel</Button>
|
||||
</Box>
|
||||
</form>
|
||||
:renderWidgets(widgets)
|
||||
}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatMark;
|
@ -14,7 +14,7 @@ import { IChatContext } from "@/views/stores/InputStore";
|
||||
|
||||
interface IProps {
|
||||
item?: IMessage,
|
||||
avatarType?: "user" | "bot" | "system",
|
||||
avatarType?: string,
|
||||
copyMessage?: string,
|
||||
messageContexts?: IChatContext[],
|
||||
deleteHash?: string,
|
||||
|
@ -13,6 +13,9 @@ import { Message } from "@/views/stores/ChatStore";
|
||||
import messageUtil from '@/util/MessageUtil';
|
||||
import {fromMarkdown} from 'mdast-util-from-markdown';
|
||||
import {visit} from 'unist-util-visit';
|
||||
import ChatMark from "@/views/components/ChatMark";
|
||||
import { useSetState } from "@mantine/hooks";
|
||||
import { toMarkdown } from "mdast-util-to-markdown";
|
||||
|
||||
interface MessageMarkdownProps extends React.ComponentProps<typeof ReactMarkdown> {
|
||||
children: string,
|
||||
@ -26,6 +29,17 @@ type Step = {
|
||||
endsWithTripleBacktick: boolean;
|
||||
};
|
||||
|
||||
function parseMetaData(string) {
|
||||
const regexp = /((?<k1>(?!=)\S+)=((?<v1>(["'`])(.*?)\5)|(?<v2>\S+)))|(?<k2>\S+)/g;
|
||||
const io = (string ?? '').matchAll(regexp);
|
||||
|
||||
return new Map(
|
||||
[...io]
|
||||
.map((item) => item?.groups)
|
||||
.map(({ k1, k2, v1, v2 }) => [k1 ?? k2, v1 ?? v2]),
|
||||
);
|
||||
}
|
||||
|
||||
const MessageMarkdown = observer((props: MessageMarkdownProps) => {
|
||||
const { children,temp=false } = props;
|
||||
const { chat } = useMst();
|
||||
@ -33,7 +47,7 @@ const MessageMarkdown = observer((props: MessageMarkdownProps) => {
|
||||
const tree = fromMarkdown(children);
|
||||
const codes = tree.children.filter(node => node.type === 'code');
|
||||
const lastNode = tree.children[tree.children.length-1];
|
||||
let index = 1;
|
||||
const [chatmarkValues,setChatmarkValues] = useSetState({});
|
||||
|
||||
const handleExplain = (value: string | undefined) => {
|
||||
console.log(value);
|
||||
@ -119,19 +133,65 @@ Generate a professionally written and formatted release note in markdown with th
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
let previousNode:any = null;
|
||||
let chatmarkCount = 0;
|
||||
visit(tree, function (node) {
|
||||
if (node.type === 'code') {
|
||||
// set meta data as props
|
||||
const metaData = parseMetaData(node.meta);
|
||||
let props = {...metaData};
|
||||
if(node.lang ==='chatmark' || node.lang ==='ChatMark'){
|
||||
props['index'] = chatmarkCount;
|
||||
} else if ((node.lang === 'yaml' || node.lang === 'YAML') && previousNode && previousNode.type === 'code' && previousNode.lang === 'chatmark') {
|
||||
setChatmarkValues({[`chatmark-${previousNode.data.hProperties.index}`]:node.value});
|
||||
}
|
||||
node.data={
|
||||
hProperties:{
|
||||
...props
|
||||
}
|
||||
};
|
||||
// record node and count data for next loop
|
||||
previousNode = node;
|
||||
if(node.lang ==='chatmark' || node.lang ==='ChatMark'){
|
||||
chatmarkCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
},[children]);
|
||||
|
||||
return <ReactMarkdown
|
||||
{...props}
|
||||
remarkPlugins={[()=> (tree) =>{
|
||||
let stepCount = 1;
|
||||
let chatmarkCount = 0;
|
||||
visit(tree, function (node) {
|
||||
if (node.type === 'code' && (node.lang ==='step' || node.lang ==='Step')) {
|
||||
node.data = {
|
||||
if (node.type === 'code') {
|
||||
// set meta data as props
|
||||
const metaData = parseMetaData(node.meta);
|
||||
let props = {...metaData};
|
||||
if(node.lang ==='step' || node.lang ==='Step'){
|
||||
props['index'] = stepCount;
|
||||
} else if(node.lang ==='chatmark' || node.lang ==='ChatMark'){
|
||||
props['id'] = `chatmark-${chatmarkCount}`;
|
||||
props['index'] = chatmarkCount;
|
||||
}
|
||||
node.data={
|
||||
hProperties:{
|
||||
index: index++
|
||||
...props
|
||||
}
|
||||
};
|
||||
// record node and count data for next loop
|
||||
if(node.lang ==='chatmark' || node.lang ==='ChatMark'){
|
||||
chatmarkCount++;
|
||||
}
|
||||
if(node.lang ==='step' || node.lang ==='Step'){
|
||||
stepCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
}]}
|
||||
|
||||
rehypePlugins={[rehypeRaw]}
|
||||
components={{
|
||||
code({ node, inline, className, children, index, ...props }) {
|
||||
@ -153,6 +213,11 @@ Generate a professionally written and formatted release note in markdown with th
|
||||
return <Step language={lanugage} done={temp?done:true}>{value}</Step>;
|
||||
}
|
||||
|
||||
if (lanugage === 'chatmark' || lanugage === 'ChatMark') {
|
||||
const chatmarkValue = chatmarkValues[`chatmark-${index}`];
|
||||
return <ChatMark value={chatmarkValue}>{value}</ChatMark>;
|
||||
}
|
||||
|
||||
return !inline && lanugage ? (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<LanguageCorner language={lanugage} />
|
||||
|
@ -3,6 +3,7 @@ import messageUtil from '@/util/MessageUtil';
|
||||
import { ChatContext } from '@/views/stores/InputStore';
|
||||
import { features } from "process";
|
||||
import { Slice } from "@tiptap/pm/model";
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
interface Context {
|
||||
content: string;
|
||||
@ -201,6 +202,20 @@ You can configure DevChat from [Settings](#settings).`;
|
||||
goScrollBottom();
|
||||
};
|
||||
|
||||
const userInput = (values:any) => {
|
||||
const inputStr = `
|
||||
\`\`\`yaml type=chatmark-values
|
||||
${yaml.dump(values)}
|
||||
\`\`\`
|
||||
`;
|
||||
self.currentMessage = self.currentMessage + inputStr;
|
||||
messageUtil.sendMessage({
|
||||
command: 'userInput',
|
||||
text: inputStr
|
||||
});
|
||||
// goto bottom
|
||||
goScrollBottom();
|
||||
};
|
||||
|
||||
return {
|
||||
helpMessage,
|
||||
@ -209,6 +224,7 @@ You can configure DevChat from [Settings](#settings).`;
|
||||
goScrollBottom,
|
||||
startGenerating,
|
||||
commonMessage,
|
||||
userInput,
|
||||
devchatAsk : flow(function* (userMessage, chatContexts) {
|
||||
self.messages.push({
|
||||
type: 'user',
|
||||
|
Loading…
x
Reference in New Issue
Block a user