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