From 2387a622e1d6565b12254dfe3c18c9360261b3b5 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 20 Jun 2023 12:01:01 +0200 Subject: [PATCH 01/10] basic gpt impl --- apps/remix-ide/src/app.js | 9 +++-- apps/remix-ide/src/app/plugins/openaigpt.tsx | 37 ++++++++++++++++++++ libs/remix-ui/renderer/src/lib/renderer.tsx | 16 +++++++++ package.json | 1 + yarn.lock | 8 +++++ 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 apps/remix-ide/src/app/plugins/openaigpt.tsx diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index b06efcf956..cbcd019abc 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -46,6 +46,7 @@ import {FileDecorator} from './app/plugins/file-decorator' import {CodeFormat} from './app/plugins/code-format' import {SolidityUmlGen} from './app/plugins/solidity-umlgen' import {ContractFlattener} from './app/plugins/contractFlattener' +import {OpenAIGpt} from './app/plugins/openaigpt' const isElectron = require('is-electron') @@ -180,6 +181,9 @@ class AppComponent { // ----------------- ContractFlattener ---------------------------- const contractFlattener = new ContractFlattener() + // ----------------- Open AI -------------------------------------- + const openaigpt = new OpenAIGpt() + // ----------------- import content service ------------------------ const contentImport = new CompilerImports() @@ -297,7 +301,8 @@ class AppComponent { search, solidityumlgen, contractFlattener, - solidityScript + solidityScript, + openaigpt ]) // LAYOUT & SYSTEM VIEWS @@ -410,7 +415,7 @@ class AppComponent { ]) await this.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder']) - await this.appManager.activatePlugin(['solidity-script']) + await this.appManager.activatePlugin(['solidity-script', 'openaigpt']) this.appManager.on('filePanel', 'workspaceInitializationCompleted', async () => { // for e2e tests diff --git a/apps/remix-ide/src/app/plugins/openaigpt.tsx b/apps/remix-ide/src/app/plugins/openaigpt.tsx new file mode 100644 index 0000000000..c2c51e88a6 --- /dev/null +++ b/apps/remix-ide/src/app/plugins/openaigpt.tsx @@ -0,0 +1,37 @@ +import { Plugin } from '@remixproject/engine' +import { OpenAIApi, CreateChatCompletionResponse } from 'openai' + +const _paq = window._paq = window._paq || [] + +const profile = { + name: 'openaigpt', + displayName: 'openaigpt', + description: 'openaigpt', + methods: ['message'], + events: [], + maintainedBy: 'Remix', +} + +export class OpenAIGpt extends Plugin { + openai: OpenAIApi + + constructor() { + super(profile) + } + + async message(prompt): Promise { + this.call('terminal', 'log', 'Waiting for GPT answer...') + const result = await (await fetch('https://openai-gpt.remixproject.org', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({prompt}) + })).json() + + console.log(result) + this.call('terminal', 'log', { type: 'typewriterlog', value: result.choices[0].message.content }) + return result.data + } +} \ No newline at end of file diff --git a/libs/remix-ui/renderer/src/lib/renderer.tsx b/libs/remix-ui/renderer/src/lib/renderer.tsx index 41d860bc18..fd1f410026 100644 --- a/libs/remix-ui/renderer/src/lib/renderer.tsx +++ b/libs/remix-ui/renderer/src/lib/renderer.tsx @@ -67,6 +67,21 @@ export const Renderer = ({message, opt = {}, plugin}: RendererProps) => { } } + const askGtp = async () => { + try { + const content = await plugin.call('fileManager', 'readFile', editorOptions.errFile) + const message = ` + solidity file: ${content} + error message: ${messageText} + explain which line the error occured, the reason and how to fix it. + ` + await plugin.call('openaigpt', 'message', message) + } catch (err) { + console.error('unable to askGtp') + console.error(err) + } + } + return ( <> {messageText && !close && ( @@ -82,6 +97,7 @@ export const Renderer = ({message, opt = {}, plugin}: RendererProps) => { + { askGtp() }}>ASK GPT )} diff --git a/package.json b/package.json index a435925994..48bff5484a 100644 --- a/package.json +++ b/package.json @@ -178,6 +178,7 @@ "latest-version": "^5.1.0", "merge": "^2.1.1", "npm-install-version": "^6.0.2", + "openai": "^3.3.0", "path-browserify": "^1.0.1", "prettier": "^2.8.4", "prettier-plugin-solidity": "^1.0.0-beta.24", diff --git a/yarn.lock b/yarn.lock index 0fbc819922..ffcbd9053a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21152,6 +21152,14 @@ open@^8.0.9, open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +openai@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/openai/-/openai-3.3.0.tgz#a6408016ad0945738e1febf43f2fccca83a3f532" + integrity sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ== + dependencies: + axios "^0.26.0" + form-data "^4.0.0" + opener@^1.5.1, opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" From b3eef9cf58b7f381ad772e36a33dff0c2faf3269 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 20 Jun 2023 13:02:23 +0200 Subject: [PATCH 02/10] better message --- libs/remix-ui/renderer/src/lib/renderer.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/remix-ui/renderer/src/lib/renderer.tsx b/libs/remix-ui/renderer/src/lib/renderer.tsx index fd1f410026..ac491b28d8 100644 --- a/libs/remix-ui/renderer/src/lib/renderer.tsx +++ b/libs/remix-ui/renderer/src/lib/renderer.tsx @@ -71,11 +71,11 @@ export const Renderer = ({message, opt = {}, plugin}: RendererProps) => { try { const content = await plugin.call('fileManager', 'readFile', editorOptions.errFile) const message = ` - solidity file: ${content} + solidity code: ${content} error message: ${messageText} - explain which line the error occured, the reason and how to fix it. + explain why the error occurred and how to fix it. ` - await plugin.call('openaigpt', 'message', message) + await plugin.call('openaigpt', 'message', message) } catch (err) { console.error('unable to askGtp') console.error(err) From 1a24f77a67fe27f2024972ba19876d89d5e13034 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 20 Jun 2023 13:02:45 +0200 Subject: [PATCH 03/10] add right click menu action for documentation and explanation --- .../editor/src/lib/remix-ui-editor.tsx | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx index 55d5c4025c..080284f0be 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx @@ -152,6 +152,7 @@ export const EditorUI = (props: EditorUIProps) => { const pasteCodeRef = useRef(false) const editorRef = useRef(null) const monacoRef = useRef(null) + const currentFunction = useRef('') const currentFileRef = useRef('') const currentUrlRef = useRef('') // const currentDecorations = useRef({ sourceAnnotationsPerFile: {}, markerPerFile: {} }) // decorations that are currently in use by the editor @@ -683,7 +684,43 @@ export const EditorUI = (props: EditorUIProps) => { } } - const freeFunctionCondition = editor.createContextKey('freeFunctionCondition', false) + let gptGenerateDocumentationAction + const executeGptGenerateDocumentationAction = { + id: "generateDocumentation", + label: "Generate documentation for this function", + contextMenuOrder: 0, // choose the order + contextMenuGroupId: "gtp", // create a new grouping + keybindings: [], + run: async () => { + const file = await props.plugin.call('fileManager', 'getCurrentFile') + const content = await props.plugin.call('fileManager', 'readFile', file) + const message = ` + solidity code: ${content} + Generate the documentation for the function ${currentFunction.current} using the Doxygen style syntax + ` + await props.plugin.call('openaigpt', 'message', message) + }, + } + + let gptExplainFunctionAction + const executegptExplainFunctionAction = { + id: "generateDocumentation", + label: "Explain this function", + contextMenuOrder: 0, // choose the order + contextMenuGroupId: "gtp", // create a new grouping + keybindings: [], + run: async () => { + const file = await props.plugin.call('fileManager', 'getCurrentFile') + const content = await props.plugin.call('fileManager', 'readFile', file) + const message = ` + solidity code: ${content} + Explain the function ${currentFunction.current} + ` + await props.plugin.call('openaigpt', 'message', message) + }, + } + + const freeFunctionCondition = editor.createContextKey('freeFunctionCondition', false); let freeFunctionAction const executeFreeFunctionAction = { id: 'executeFreeFunction', @@ -695,7 +732,7 @@ export const EditorUI = (props: EditorUIProps) => { // eslint-disable-next-line no-bitwise monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR ], - run: async () => { + run: async () => { const {nodesAtPosition} = await retrieveNodesAtPosition(props.editorAPI, props.plugin) // find the contract and get the nodes of the contract and the base contracts and imports if (nodesAtPosition && isArray(nodesAtPosition) && nodesAtPosition.length) { @@ -715,6 +752,8 @@ export const EditorUI = (props: EditorUIProps) => { editor.addAction(zoomOutAction) editor.addAction(zoominAction) freeFunctionAction = editor.addAction(executeFreeFunctionAction) + gptGenerateDocumentationAction = editor.addAction(executeGptGenerateDocumentationAction) + gptExplainFunctionAction = editor.addAction(executegptExplainFunctionAction) // we have to add the command because the menu action isn't always available (see onContextMenuHandlerForFreeFunction) editor.addCommand(monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR, () => executeFreeFunctionAction.run()) @@ -726,6 +765,15 @@ export const EditorUI = (props: EditorUIProps) => { freeFunctionAction.dispose() freeFunctionAction = null } + if (gptGenerateDocumentationAction) { + gptGenerateDocumentationAction.dispose() + gptGenerateDocumentationAction = null + } + if (gptExplainFunctionAction) { + gptExplainFunctionAction.dispose() + gptExplainFunctionAction = null + } + const file = await props.plugin.call('fileManager', 'getCurrentFile') if (!file.endsWith('.sol')) { freeFunctionCondition.set(false) @@ -737,6 +785,14 @@ export const EditorUI = (props: EditorUIProps) => { executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}" in the Remix VM` freeFunctionAction = editor.addAction(executeFreeFunctionAction) } + const functionImpl = nodesAtPosition.find((node) => node.kind === 'function') + if (functionImpl) { + currentFunction.current = functionImpl.name + executeGptGenerateDocumentationAction.label = `Generate documentation for the function "${functionImpl.name}"` + gptGenerateDocumentationAction = editor.addAction(executeGptGenerateDocumentationAction) + executegptExplainFunctionAction.label = `Explain the function "${functionImpl.name}"` + gptExplainFunctionAction = editor.addAction(executegptExplainFunctionAction) + } freeFunctionCondition.set(!!freeFunctionNode) } contextmenu._onContextMenu = (...args) => { From 7fe12b92ede367c296ceb8fc59348e7480efca53 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 20 Jun 2023 17:20:27 +0200 Subject: [PATCH 04/10] type writer --- apps/remix-ide/src/app/plugins/openaigpt.tsx | 2 +- .../src/lib/reducers/terminalReducer.ts | 7 ++- .../terminal/src/lib/remix-ui-terminal.tsx | 50 +++++++++++++++---- .../terminal/src/lib/types/terminalTypes.ts | 1 + 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/openaigpt.tsx b/apps/remix-ide/src/app/plugins/openaigpt.tsx index c2c51e88a6..e7fe7ecc85 100644 --- a/apps/remix-ide/src/app/plugins/openaigpt.tsx +++ b/apps/remix-ide/src/app/plugins/openaigpt.tsx @@ -31,7 +31,7 @@ export class OpenAIGpt extends Plugin { })).json() console.log(result) - this.call('terminal', 'log', { type: 'typewriterlog', value: result.choices[0].message.content }) + this.call('terminal', 'log', { type: 'typewritersuccess', value: result.choices[0].message.content }) return result.data } } \ No newline at end of file diff --git a/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts b/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts index 61ba9d85fc..38f860fb84 100644 --- a/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts +++ b/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts @@ -1,4 +1,4 @@ -import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes' +import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, TYPEWRITERLOG, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes' export const initialState = { journalBlocks: [ @@ -151,6 +151,11 @@ export const registerScriptRunnerReducer = (state, action) => { ...state, journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, style: 'text-log', provider: action.payload.provider }) } + case TYPEWRITERLOG: + return { + ...state, + journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-log', provider: action.payload.provider }) + } case INFO: return { ...state, diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx index db3c012714..7a6cdb002f 100644 --- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx +++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx @@ -84,6 +84,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => { // terminal inputRef const inputEl = useRef(null) const messagesEndRef = useRef(null) + const typeWriterIndexes = useRef([]) // terminal dragable const panelRef = useRef(null) @@ -389,6 +390,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => { const handleClearConsole = () => { setClearConsole(true) + typeWriterIndexes.current = [] dispatch({ type: 'clearconsole', payload: [] }) inputEl.current.focus() } @@ -723,21 +725,36 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => { ) } else { - return ( -
- {msg ? msg.toString() : null} -
- ) + // typeWriterIndexes: we don't want to rerender using typewriter when the react component updates + if (x.typewriter && !typeWriterIndexes.current.includes(index)) { + typeWriterIndexes.current.push(index) + return ( +
{ + typewrite(element, msg ? msg.toString() : null) + }} className={x.style}>
+ ) + } else { + return ( +
{msg ? msg.toString() : null}
+ ) + } } }) } else { - if (typeof x.message !== 'function') { + // typeWriterIndexes: we don't want to rerender using typewriter when the react component updates + if (x.typewriter && !typeWriterIndexes.current.includes(index)) { + typeWriterIndexes.current.push(index) return ( -
- {' '} - {x.message} -
+
{ + typewrite(element, x.message) + }} className={x.style}>
) + } else { + if (typeof x.message !== 'function') { + return ( +
{x.message}
+ ) + } } } })} @@ -778,7 +795,18 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => { ) } -function isHtml(value) { +const typewrite = (elementsRef, message) => { + (() => { + let count = 0 + const id = setInterval(() => { + count++ + elementsRef.innerText = message.substr(0, count) + if (message === count) clearInterval(id) + }, 5) + })() +} + +function isHtml (value) { if (!value.indexOf) return false return value.indexOf(' Date: Mon, 26 Jun 2023 12:18:48 +0200 Subject: [PATCH 05/10] add different types of typewriter --- .../terminal/src/lib/reducers/terminalReducer.ts | 12 +++++++++++- .../remix-ui/terminal/src/lib/types/terminalTypes.ts | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts b/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts index 38f860fb84..c451abfbb8 100644 --- a/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts +++ b/libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts @@ -1,4 +1,4 @@ -import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, TYPEWRITERLOG, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes' +import { CLEAR_CONSOLE, CMD_HISTORY, EMPTY_BLOCK, ERROR, HTML, INFO, KNOWN_TRANSACTION, LISTEN_ON_NETWORK, LOG, TYPEWRITERLOG, TYPEWRITERWARNING, TYPEWRITERSUCCESS, NEW_TRANSACTION, SCRIPT, UNKNOWN_TRANSACTION, WARN } from '../types/terminalTypes' export const initialState = { journalBlocks: [ @@ -156,6 +156,16 @@ export const registerScriptRunnerReducer = (state, action) => { ...state, journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-log', provider: action.payload.provider }) } + case TYPEWRITERWARNING: + return { + ...state, + journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-warning', provider: action.payload.provider }) + } + case TYPEWRITERSUCCESS: + return { + ...state, + journalBlocks: initialState.journalBlocks.push({ message: action.payload.message, typewriter: true, style: 'text-success', provider: action.payload.provider }) + } case INFO: return { ...state, diff --git a/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts b/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts index bb18074479..d9537fcfd4 100644 --- a/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts +++ b/libs/remix-ui/terminal/src/lib/types/terminalTypes.ts @@ -16,6 +16,8 @@ export const NEW_CALL = 'newCall' export const HTML = 'html' export const LOG = 'log' export const TYPEWRITERLOG = 'typewriterlog' +export const TYPEWRITERWARNING = 'typewriterwarning' +export const TYPEWRITERSUCCESS = 'typewritersuccess' export const INFO = 'info' export const WARN = 'warn' export const ERROR = 'error' From 77f9d6d535d3deae3ee5da88a11ffbde51893ba1 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 28 Aug 2023 16:26:14 +0200 Subject: [PATCH 06/10] update ordering --- libs/remix-ui/editor/src/lib/remix-ui-editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx index 080284f0be..b494b58f45 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx @@ -706,7 +706,7 @@ export const EditorUI = (props: EditorUIProps) => { const executegptExplainFunctionAction = { id: "generateDocumentation", label: "Explain this function", - contextMenuOrder: 0, // choose the order + contextMenuOrder: 1, // choose the order contextMenuGroupId: "gtp", // create a new grouping keybindings: [], run: async () => { From fde9c403dd9b256f5f61d59fbd725065955de634 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 29 Aug 2023 15:45:41 +0200 Subject: [PATCH 07/10] fix call to openai --- apps/remix-ide/src/app/plugins/openaigpt.tsx | 28 +- .../editor/src/lib/remix-ui-editor.tsx | 265 +++++++++--------- yarn.lock | 7 + 3 files changed, 154 insertions(+), 146 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/openaigpt.tsx b/apps/remix-ide/src/app/plugins/openaigpt.tsx index e7fe7ecc85..6d0a52667f 100644 --- a/apps/remix-ide/src/app/plugins/openaigpt.tsx +++ b/apps/remix-ide/src/app/plugins/openaigpt.tsx @@ -1,7 +1,7 @@ import { Plugin } from '@remixproject/engine' -import { OpenAIApi, CreateChatCompletionResponse } from 'openai' +import { CreateChatCompletionResponse } from 'openai' -const _paq = window._paq = window._paq || [] +const _paq = (window._paq = window._paq || []) const profile = { name: 'openaigpt', @@ -13,25 +13,25 @@ const profile = { } export class OpenAIGpt extends Plugin { - openai: OpenAIApi - constructor() { super(profile) } async message(prompt): Promise { this.call('terminal', 'log', 'Waiting for GPT answer...') - const result = await (await fetch('https://openai-gpt.remixproject.org', { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({prompt}) - })).json() - + const result = await ( + await fetch('https://openai-gpt.remixproject.org', { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ prompt }), + }) + ).json() + console.log(result) this.call('terminal', 'log', { type: 'typewritersuccess', value: result.choices[0].message.content }) return result.data } -} \ No newline at end of file +} diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx index b494b58f45..691c8955e9 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx @@ -1,30 +1,30 @@ -import React, {useState, useRef, useEffect, useReducer} from 'react' // eslint-disable-line -import {isArray} from 'lodash' -import Editor, {loader, Monaco} from '@monaco-editor/react' -import {AlertModal} from '@remix-ui/app' -import {reducerActions, reducerListener, initialState} from './actions/editor' -import {solidityTokensProvider, solidityLanguageConfig} from './syntaxes/solidity' -import {cairoTokensProvider, cairoLanguageConfig} from './syntaxes/cairo' -import {zokratesTokensProvider, zokratesLanguageConfig} from './syntaxes/zokrates' -import {moveTokenProvider, moveLanguageConfig} from './syntaxes/move' -import {monacoTypes} from '@remix-ui/editor' -import {loadTypes} from './web-types' -import {retrieveNodesAtPosition} from './helpers/retrieveNodesAtPosition' -import {RemixHoverProvider} from './providers/hoverProvider' -import {RemixReferenceProvider} from './providers/referenceProvider' -import {RemixCompletionProvider} from './providers/completionProvider' -import {RemixHighLightProvider} from './providers/highlightProvider' -import {RemixDefinitionProvider} from './providers/definitionProvider' -import {RemixCodeActionProvider} from './providers/codeActionProvider' +import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line +import { isArray } from 'lodash' +import Editor, { loader, Monaco } from '@monaco-editor/react' +import { AlertModal } from '@remix-ui/app' +import { reducerActions, reducerListener, initialState } from './actions/editor' +import { solidityTokensProvider, solidityLanguageConfig } from './syntaxes/solidity' +import { cairoTokensProvider, cairoLanguageConfig } from './syntaxes/cairo' +import { zokratesTokensProvider, zokratesLanguageConfig } from './syntaxes/zokrates' +import { moveTokenProvider, moveLanguageConfig } from './syntaxes/move' +import { monacoTypes } from '@remix-ui/editor' +import { loadTypes } from './web-types' +import { retrieveNodesAtPosition } from './helpers/retrieveNodesAtPosition' +import { RemixHoverProvider } from './providers/hoverProvider' +import { RemixReferenceProvider } from './providers/referenceProvider' +import { RemixCompletionProvider } from './providers/completionProvider' +import { RemixHighLightProvider } from './providers/highlightProvider' +import { RemixDefinitionProvider } from './providers/definitionProvider' +import { RemixCodeActionProvider } from './providers/codeActionProvider' import './remix-ui-editor.css' -import {circomLanguageConfig, circomTokensProvider} from './syntaxes/circom' -import {IPosition} from 'monaco-editor' +import { circomLanguageConfig, circomTokensProvider } from './syntaxes/circom' +import { IPosition } from 'monaco-editor' enum MarkerSeverity { Hint = 1, Info = 2, Warning = 4, - Error = 8 + Error = 8, } type sourceAnnotation = { @@ -86,7 +86,7 @@ type errorMarker = { file: string } -loader.config({paths: {vs: 'assets/js/monaco-editor/min/vs'}}) +loader.config({ paths: { vs: 'assets/js/monaco-editor/min/vs' } }) export type DecorationsReturn = { currentDecorations: Array @@ -108,7 +108,8 @@ export type EditorAPIType = { clearDecorationsByPlugin: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn keepDecorationsFor: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn addErrorMarker: (errors: errorMarker[], from: string) => void - clearErrorMarkers: (sources: string[] | {[fileName: string]: any}, from: string) => void + clearErrorMarkers: (sources: string[] | { [fileName: string]: any }, from: string) => void + getPositionAt: (offset: number) => monacoTypes.IPosition } /* eslint-disable-next-line */ @@ -195,88 +196,88 @@ export const EditorUI = (props: EditorUIProps) => { base: themeType, inherit: true, // can also be false to completely replace the builtin rules rules: [ - {background: darkColor.replace('#', '')}, - {foreground: textColor.replace('#', '')}, + { background: darkColor.replace('#', '') }, + { foreground: textColor.replace('#', '') }, // global variables - {token: 'keyword.abi', foreground: blueColor}, - {token: 'keyword.block', foreground: blueColor}, - {token: 'keyword.bytes', foreground: blueColor}, - {token: 'keyword.msg', foreground: blueColor}, - {token: 'keyword.tx', foreground: blueColor}, + { token: 'keyword.abi', foreground: blueColor }, + { token: 'keyword.block', foreground: blueColor }, + { token: 'keyword.bytes', foreground: blueColor }, + { token: 'keyword.msg', foreground: blueColor }, + { token: 'keyword.tx', foreground: blueColor }, // global functions - {token: 'keyword.assert', foreground: blueColor}, - {token: 'keyword.require', foreground: blueColor}, - {token: 'keyword.revert', foreground: blueColor}, - {token: 'keyword.blockhash', foreground: blueColor}, - {token: 'keyword.keccak256', foreground: blueColor}, - {token: 'keyword.sha256', foreground: blueColor}, - {token: 'keyword.ripemd160', foreground: blueColor}, - {token: 'keyword.ecrecover', foreground: blueColor}, - {token: 'keyword.addmod', foreground: blueColor}, - {token: 'keyword.mulmod', foreground: blueColor}, - {token: 'keyword.selfdestruct', foreground: blueColor}, - {token: 'keyword.type ', foreground: blueColor}, - {token: 'keyword.gasleft', foreground: blueColor}, + { token: 'keyword.assert', foreground: blueColor }, + { token: 'keyword.require', foreground: blueColor }, + { token: 'keyword.revert', foreground: blueColor }, + { token: 'keyword.blockhash', foreground: blueColor }, + { token: 'keyword.keccak256', foreground: blueColor }, + { token: 'keyword.sha256', foreground: blueColor }, + { token: 'keyword.ripemd160', foreground: blueColor }, + { token: 'keyword.ecrecover', foreground: blueColor }, + { token: 'keyword.addmod', foreground: blueColor }, + { token: 'keyword.mulmod', foreground: blueColor }, + { token: 'keyword.selfdestruct', foreground: blueColor }, + { token: 'keyword.type ', foreground: blueColor }, + { token: 'keyword.gasleft', foreground: blueColor }, // specials - {token: 'keyword.super', foreground: infoColor}, - {token: 'keyword.this', foreground: infoColor}, - {token: 'keyword.virtual', foreground: infoColor}, + { token: 'keyword.super', foreground: infoColor }, + { token: 'keyword.this', foreground: infoColor }, + { token: 'keyword.virtual', foreground: infoColor }, // for state variables - {token: 'keyword.constants', foreground: grayColor}, - {token: 'keyword.override', foreground: grayColor}, - {token: 'keyword.immutable', foreground: grayColor}, + { token: 'keyword.constants', foreground: grayColor }, + { token: 'keyword.override', foreground: grayColor }, + { token: 'keyword.immutable', foreground: grayColor }, // data location - {token: 'keyword.memory', foreground: locationColor}, - {token: 'keyword.storage', foreground: locationColor}, - {token: 'keyword.calldata', foreground: locationColor}, + { token: 'keyword.memory', foreground: locationColor }, + { token: 'keyword.storage', foreground: locationColor }, + { token: 'keyword.calldata', foreground: locationColor }, // for Events - {token: 'keyword.indexed', foreground: yellowColor}, - {token: 'keyword.anonymous', foreground: yellowColor}, + { token: 'keyword.indexed', foreground: yellowColor }, + { token: 'keyword.anonymous', foreground: yellowColor }, // for functions - {token: 'keyword.external', foreground: successColor}, - {token: 'keyword.internal', foreground: successColor}, - {token: 'keyword.private', foreground: successColor}, - {token: 'keyword.public', foreground: successColor}, - {token: 'keyword.view', foreground: successColor}, - {token: 'keyword.pure', foreground: successColor}, - {token: 'keyword.payable', foreground: successColor}, - {token: 'keyword.nonpayable', foreground: successColor}, + { token: 'keyword.external', foreground: successColor }, + { token: 'keyword.internal', foreground: successColor }, + { token: 'keyword.private', foreground: successColor }, + { token: 'keyword.public', foreground: successColor }, + { token: 'keyword.view', foreground: successColor }, + { token: 'keyword.pure', foreground: successColor }, + { token: 'keyword.payable', foreground: successColor }, + { token: 'keyword.nonpayable', foreground: successColor }, // Errors - {token: 'keyword.Error', foreground: dangerColor}, - {token: 'keyword.Panic', foreground: dangerColor}, + { token: 'keyword.Error', foreground: dangerColor }, + { token: 'keyword.Panic', foreground: dangerColor }, // special functions - {token: 'keyword.fallback', foreground: pinkColor}, - {token: 'keyword.receive', foreground: pinkColor}, - {token: 'keyword.constructor', foreground: pinkColor}, + { token: 'keyword.fallback', foreground: pinkColor }, + { token: 'keyword.receive', foreground: pinkColor }, + { token: 'keyword.constructor', foreground: pinkColor }, // identifiers - {token: 'keyword.identifier', foreground: warningColor}, - {token: 'keyword.for', foreground: warningColor}, - {token: 'keyword.break', foreground: warningColor}, - {token: 'keyword.continue', foreground: warningColor}, - {token: 'keyword.while', foreground: warningColor}, - {token: 'keyword.do', foreground: warningColor}, - {token: 'keyword.delete', foreground: warningColor}, + { token: 'keyword.identifier', foreground: warningColor }, + { token: 'keyword.for', foreground: warningColor }, + { token: 'keyword.break', foreground: warningColor }, + { token: 'keyword.continue', foreground: warningColor }, + { token: 'keyword.while', foreground: warningColor }, + { token: 'keyword.do', foreground: warningColor }, + { token: 'keyword.delete', foreground: warningColor }, - {token: 'keyword.if', foreground: yellowColor}, - {token: 'keyword.else', foreground: yellowColor}, + { token: 'keyword.if', foreground: yellowColor }, + { token: 'keyword.else', foreground: yellowColor }, - {token: 'keyword.throw', foreground: orangeColor}, - {token: 'keyword.catch', foreground: orangeColor}, - {token: 'keyword.try', foreground: orangeColor}, + { token: 'keyword.throw', foreground: orangeColor }, + { token: 'keyword.catch', foreground: orangeColor }, + { token: 'keyword.try', foreground: orangeColor }, // returns - {token: 'keyword.returns', foreground: greenColor}, - {token: 'keyword.return', foreground: greenColor} + { token: 'keyword.returns', foreground: greenColor }, + { token: 'keyword.return', foreground: greenColor }, ], colors: { // see https://code.visualstudio.com/api/references/theme-color for more settings @@ -295,8 +296,8 @@ export const EditorUI = (props: EditorUIProps) => { 'menu.background': textbackground, 'menu.selectionBackground': secondaryColor, 'menu.selectionForeground': textColor, - 'menu.selectionBorder': secondaryColor - } + 'menu.selectionBorder': secondaryColor, + }, }) monacoRef.current.editor.setTheme(themeName) } @@ -314,7 +315,7 @@ export const EditorUI = (props: EditorUIProps) => { const file = editorModelsState[props.currentFile] editorRef.current.setModel(file.model) editorRef.current.updateOptions({ - readOnly: editorModelsState[props.currentFile].readOnly + readOnly: editorModelsState[props.currentFile].readOnly, }) if (file.language === 'sol') { monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity') @@ -338,10 +339,10 @@ export const EditorUI = (props: EditorUIProps) => { options: { isWholeLine: false, glyphMarginHoverMessage: { - value: (decoration.from ? `from ${decoration.from}:\n` : '') + decoration.text + value: (decoration.from ? `from ${decoration.from}:\n` : '') + decoration.text, }, - glyphMarginClassName: `fal fa-exclamation-square text-${decoration.type === 'error' ? 'danger' : decoration.type === 'warning' ? 'warning' : 'info'}` - } + glyphMarginClassName: `fal fa-exclamation-square text-${decoration.type === 'error' ? 'danger' : decoration.type === 'warning' ? 'warning' : 'info'}`, + }, } } if (typeOfDecoration === 'markerPerFile') { @@ -364,8 +365,8 @@ export const EditorUI = (props: EditorUIProps) => { ), options: { isWholeLine, - inlineClassName: `${isWholeLine ? 'alert-info' : 'inline-class'} border-0 highlightLine${decoration.position.start.line + 1}` - } + inlineClassName: `${isWholeLine ? 'alert-info' : 'inline-class'} border-0 highlightLine${decoration.position.start.line + 1}`, + }, } } if (typeOfDecoration === 'lineTextPerFile') { @@ -381,11 +382,11 @@ export const EditorUI = (props: EditorUIProps) => { options: { after: { content: ` ${lineTextDecoration.content}`, - inlineClassName: `${lineTextDecoration.className}` + inlineClassName: `${lineTextDecoration.className}`, }, afterContentClassName: `${lineTextDecoration.afterContentClassName}`, - hoverMessage: lineTextDecoration.hoverMessage - } + hoverMessage: lineTextDecoration.hoverMessage, + }, } } if (typeOfDecoration === 'lineTextPerFile') { @@ -401,11 +402,11 @@ export const EditorUI = (props: EditorUIProps) => { options: { after: { content: ` ${lineTextDecoration.content}`, - inlineClassName: `${lineTextDecoration.className}` + inlineClassName: `${lineTextDecoration.className}`, }, afterContentClassName: `${lineTextDecoration.afterContentClassName}`, - hoverMessage: lineTextDecoration.hoverMessage - } + hoverMessage: lineTextDecoration.hoverMessage, + }, } } } @@ -415,7 +416,7 @@ export const EditorUI = (props: EditorUIProps) => { if (!model) return { currentDecorations: [], - registeredDecorations: [] + registeredDecorations: [], } const decorations = [] const newRegisteredDecorations = [] @@ -429,7 +430,7 @@ export const EditorUI = (props: EditorUIProps) => { } return { currentDecorations: model.deltaDecorations(currentDecorations, decorations), - registeredDecorations: newRegisteredDecorations + registeredDecorations: newRegisteredDecorations, } } @@ -437,7 +438,7 @@ export const EditorUI = (props: EditorUIProps) => { const model = editorModelsState[filePath]?.model if (!model) return { - currentDecorations: [] + currentDecorations: [], } const decorations = [] if (registeredDecorations) { @@ -448,17 +449,17 @@ export const EditorUI = (props: EditorUIProps) => { } } return { - currentDecorations: model.deltaDecorations(currentDecorations, decorations) + currentDecorations: model.deltaDecorations(currentDecorations, decorations), } } const addDecoration = (decoration: sourceAnnotation | sourceMarker, filePath: string, typeOfDecoration: string) => { const model = editorModelsState[filePath]?.model - if (!model) return {currentDecorations: []} + if (!model) return { currentDecorations: [] } const monacoDecoration = convertToMonacoDecoration(decoration, typeOfDecoration) return { currentDecorations: model.deltaDecorations([], [monacoDecoration]), - registeredDecorations: [{value: decoration, type: typeOfDecoration}] + registeredDecorations: [{ value: decoration, type: typeOfDecoration }], } } @@ -479,7 +480,7 @@ export const EditorUI = (props: EditorUIProps) => { const errorServerityMap = { error: MarkerSeverity.Error, warning: MarkerSeverity.Warning, - info: MarkerSeverity.Info + info: MarkerSeverity.Info, } if (model) { const markerData: monacoTypes.editor.IMarkerData = { @@ -488,7 +489,7 @@ export const EditorUI = (props: EditorUIProps) => { startColumn: (error.position.start && error.position.start.column) || 0, endLineNumber: (error.position.end && error.position.end.line) || 0, endColumn: (error.position.end && error.position.end.column) || 0, - message: error.message + message: error.message, } if (!allMarkersPerfile[filePath]) { allMarkersPerfile[filePath] = [] @@ -504,7 +505,7 @@ export const EditorUI = (props: EditorUIProps) => { } } - props.editorAPI.clearErrorMarkers = async (sources: string[] | {[fileName: string]: any}, from: string) => { + props.editorAPI.clearErrorMarkers = async (sources: string[] | { [fileName: string]: any }, from: string) => { if (sources) { for (const source of Array.isArray(sources) ? sources : Object.keys(sources)) { const filePath = source @@ -573,9 +574,9 @@ export const EditorUI = (props: EditorUIProps) => { range: new monacoRef.current.Range(position.lineNumber, 1, position.lineNumber, 1), options: { isWholeLine: false, - glyphMarginClassName: 'fas fa-circle text-info' - } - } + glyphMarginClassName: 'fas fa-circle text-info', + }, + }, ] ) prevState[currentFile][position.lineNumber] = decorationIds[0] @@ -627,7 +628,7 @@ export const EditorUI = (props: EditorUIProps) => { - ) + ), } props.plugin.call('notification', 'alert', modalContent) pasteCodeRef.current = true @@ -650,7 +651,7 @@ export const EditorUI = (props: EditorUIProps) => { contextMenuGroupId: 'zooming', // create a new grouping keybindings: [ // eslint-disable-next-line no-bitwise - monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Equal + monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Equal, ], run: () => { editor.updateOptions({fontSize: editor.getOption(51) + 1}) @@ -663,7 +664,7 @@ export const EditorUI = (props: EditorUIProps) => { contextMenuGroupId: 'zooming', // create a new grouping keybindings: [ // eslint-disable-next-line no-bitwise - monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Minus + monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Minus, ], run: () => { editor.updateOptions({fontSize: editor.getOption(51) - 1}) @@ -676,20 +677,20 @@ export const EditorUI = (props: EditorUIProps) => { contextMenuGroupId: 'formatting', // create a new grouping keybindings: [ // eslint-disable-next-line no-bitwise - monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyF + monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyF, ], run: async () => { const file = await props.plugin.call('fileManager', 'getCurrentFile') await props.plugin.call('codeFormatter', 'format', file) - } + }, } let gptGenerateDocumentationAction const executeGptGenerateDocumentationAction = { - id: "generateDocumentation", - label: "Generate documentation for this function", + id: 'generateDocumentation', + label: 'Generate documentation for this function', contextMenuOrder: 0, // choose the order - contextMenuGroupId: "gtp", // create a new grouping + contextMenuGroupId: 'gtp', // create a new grouping keybindings: [], run: async () => { const file = await props.plugin.call('fileManager', 'getCurrentFile') @@ -704,10 +705,10 @@ export const EditorUI = (props: EditorUIProps) => { let gptExplainFunctionAction const executegptExplainFunctionAction = { - id: "generateDocumentation", - label: "Explain this function", + id: 'explainFunction', + label: 'Explain this function', contextMenuOrder: 1, // choose the order - contextMenuGroupId: "gtp", // create a new grouping + contextMenuGroupId: 'gtp', // create a new grouping keybindings: [], run: async () => { const file = await props.plugin.call('fileManager', 'getCurrentFile') @@ -720,7 +721,7 @@ export const EditorUI = (props: EditorUIProps) => { }, } - const freeFunctionCondition = editor.createContextKey('freeFunctionCondition', false); + const freeFunctionCondition = editor.createContextKey('freeFunctionCondition', false) let freeFunctionAction const executeFreeFunctionAction = { id: 'executeFreeFunction', @@ -730,10 +731,10 @@ export const EditorUI = (props: EditorUIProps) => { precondition: 'freeFunctionCondition', keybindings: [ // eslint-disable-next-line no-bitwise - monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR + monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyR, ], - run: async () => { - const {nodesAtPosition} = await retrieveNodesAtPosition(props.editorAPI, props.plugin) + run: async () => { + const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin) // find the contract and get the nodes of the contract and the base contracts and imports if (nodesAtPosition && isArray(nodesAtPosition) && nodesAtPosition.length) { const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction') @@ -746,7 +747,7 @@ export const EditorUI = (props: EditorUIProps) => { } else { props.plugin.call('notification', 'toast', 'Please go to Remix settings and activate the code editor features or wait that the current editor context is loaded.') } - } + }, } editor.addAction(formatAction) editor.addAction(zoomOutAction) @@ -779,13 +780,13 @@ export const EditorUI = (props: EditorUIProps) => { freeFunctionCondition.set(false) return } - const {nodesAtPosition} = await retrieveNodesAtPosition(props.editorAPI, props.plugin) + const { nodesAtPosition } = await retrieveNodesAtPosition(props.editorAPI, props.plugin) const freeFunctionNode = nodesAtPosition.find((node) => node.kind === 'freeFunction') if (freeFunctionNode) { executeFreeFunctionAction.label = `Run the free function "${freeFunctionNode.name}" in the Remix VM` freeFunctionAction = editor.addAction(executeFreeFunctionAction) } - const functionImpl = nodesAtPosition.find((node) => node.kind === 'function') + const functionImpl = nodesAtPosition.find((node) => node.kind === 'function') if (functionImpl) { currentFunction.current = functionImpl.name executeGptGenerateDocumentationAction.label = `Generate documentation for the function "${functionImpl.name}"` @@ -813,7 +814,7 @@ export const EditorUI = (props: EditorUIProps) => { editor.revealRange(input.options.selection) editor.setPosition({ column: input.options.selection.startColumn, - lineNumber: input.options.selection.startLineNumber + lineNumber: input.options.selection.startLineNumber, }) } } catch (e) { @@ -831,11 +832,11 @@ export const EditorUI = (props: EditorUIProps) => { function handleEditorWillMount(monaco) { monacoRef.current = monaco // Register a new language - monacoRef.current.languages.register({id: 'remix-solidity'}) - monacoRef.current.languages.register({id: 'remix-cairo'}) - monacoRef.current.languages.register({id: 'remix-zokrates'}) - monacoRef.current.languages.register({id: 'remix-move'}) - monacoRef.current.languages.register({id: 'remix-circom'}) + monacoRef.current.languages.register({ id: 'remix-solidity' }) + monacoRef.current.languages.register({ id: 'remix-cairo' }) + monacoRef.current.languages.register({ id: 'remix-zokrates' }) + monacoRef.current.languages.register({ id: 'remix-move' }) + monacoRef.current.languages.register({ id: 'remix-circom' }) // Register a tokens provider for the language monacoRef.current.languages.setMonarchTokensProvider('remix-solidity', solidityTokensProvider as any) @@ -873,7 +874,7 @@ export const EditorUI = (props: EditorUIProps) => { beforeMount={handleEditorWillMount} options={{ glyphMargin: true, - readOnly: (!editorRef.current || !props.currentFile) && editorModelsState[props.currentFile]?.readOnly + readOnly: (!editorRef.current || !props.currentFile) && editorModelsState[props.currentFile]?.readOnly, }} defaultValue={defaultEditorValue} /> diff --git a/yarn.lock b/yarn.lock index ffcbd9053a..4fec0c5f48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7812,6 +7812,13 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" +axios@^0.26.0: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + axios@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" From 142a1381fa3e7b8ea7274aa419ff811f3ecb03c7 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 31 Aug 2023 15:08:32 +0200 Subject: [PATCH 08/10] linting --- libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx index 7a6cdb002f..67a439fd29 100644 --- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx +++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx @@ -733,7 +733,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => { typewrite(element, msg ? msg.toString() : null) }} className={x.style}> ) - } else { + } else { return (
{msg ? msg.toString() : null}
) From f7e0ae3ce247aa4166bd1bbce841ead043cce18e Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 31 Aug 2023 16:42:27 +0200 Subject: [PATCH 09/10] make the code safer --- apps/remix-ide/src/app/plugins/openaigpt.tsx | 35 ++++++++++++-------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/openaigpt.tsx b/apps/remix-ide/src/app/plugins/openaigpt.tsx index 6d0a52667f..042c6da13b 100644 --- a/apps/remix-ide/src/app/plugins/openaigpt.tsx +++ b/apps/remix-ide/src/app/plugins/openaigpt.tsx @@ -19,19 +19,28 @@ export class OpenAIGpt extends Plugin { async message(prompt): Promise { this.call('terminal', 'log', 'Waiting for GPT answer...') - const result = await ( - await fetch('https://openai-gpt.remixproject.org', { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ prompt }), - }) - ).json() - - console.log(result) - this.call('terminal', 'log', { type: 'typewritersuccess', value: result.choices[0].message.content }) + let result + try { + result = await ( + await fetch('https://openai-gpt.remixproject.org', { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ prompt }), + }) + ).json() + } catch (e) { + this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` }) + return + } + + if (result && result.choices && result.choices.length) { + this.call('terminal', 'log', { type: 'typewritersuccess', value: result.choices[0].message.content }) + } else { + this.call('terminal', 'log', { type: 'typewritersuccess', value: 'No response...' }) + } return result.data } } From 94f695819355c6008104a09a4431043915a9b6fa Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 11 Sep 2023 14:18:08 +0200 Subject: [PATCH 10/10] show terminal --- apps/remix-ide/src/app/panels/layout.ts | 8 +++++++- apps/remix-ide/src/app/plugins/openaigpt.tsx | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/panels/layout.ts b/apps/remix-ide/src/app/panels/layout.ts index 3a44d1f83b..a152efc72e 100644 --- a/apps/remix-ide/src/app/panels/layout.ts +++ b/apps/remix-ide/src/app/panels/layout.ts @@ -6,7 +6,7 @@ import { QueryParams } from '@remix-project/remix-lib' const profile: Profile = { name: 'layout', description: 'layout', - methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel'] + methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel', 'maximizeTerminal'] } interface panelState { @@ -109,6 +109,12 @@ export class Layout extends Plugin { this.maximised[current] = true } + async maximizeTerminal() { + this.panels.terminal.minimized = false + this.event.emit('change', this.panels) + this.emit('change', this.panels) + } + async resetSidePanel () { this.event.emit('resetsidepanel') const current = await this.call('sidePanel', 'currentFocus') diff --git a/apps/remix-ide/src/app/plugins/openaigpt.tsx b/apps/remix-ide/src/app/plugins/openaigpt.tsx index 042c6da13b..e95babe00a 100644 --- a/apps/remix-ide/src/app/plugins/openaigpt.tsx +++ b/apps/remix-ide/src/app/plugins/openaigpt.tsx @@ -18,6 +18,7 @@ export class OpenAIGpt extends Plugin { } async message(prompt): Promise { + this.call('layout', 'maximizeTerminal') this.call('terminal', 'log', 'Waiting for GPT answer...') let result try {