feat: introduce apply button functionality (v0.1)

### Summary
- Added a new "Apply" button to code snippets provided by the AI assistant.
- The button is designed to seamlessly merge the AI-generated snippet into the relevant file in the editor.

### Current Issues
1. **Sticky Accept/Decline Buttons:** These activate for every snippet instead of being limited to the relevant snippet.
2. **Discard Button:** Currently non-functional.
3. **Highlight Inconsistencies:** The green-red code highlights for old and new code are inconsistent.

### To Do
- Implement a toast notification when the "Apply" button is pressed on an irrelevant tab to prevent code application errors.

### Workflow Implemented
1. The "Apply" button is added alongside "Copy" and "Reply" for AI-generated code snippets.
2. Upon clicking "Apply," the code snippet and relevant file content (active file) are sent to a secondary model (GPT-4O).
3. The system prompt for GPT-4O instructs it to merge the snippet with the file content:
   - Ensure the original file functionality remains intact.
   - Integrate the code snippet seamlessly.
4. The output from GPT-4O is injected directly into the code editor.
5. Changes are visually highlighted:
   - Green for new code.
   - Red for removed code.
6. Highlights remain until the user explicitly accepts or discards the changes.
This commit is contained in:
Akhileshrangani4
2024-11-30 20:56:56 -05:00
parent 534b148b86
commit 6612692d98
10 changed files with 372 additions and 5 deletions

View File

@ -104,6 +104,13 @@ export default function CodeEditor({
// Added this state to track the most recent content for each file
const [fileContents, setFileContents] = useState<Record<string, string>>({})
// Apply Button merger decoration state
const [mergeDecorations, setMergeDecorations] = useState<
monaco.editor.IModelDeltaDecoration[]
>([])
const [mergeDecorationsCollection, setMergeDecorationsCollection] =
useState<monaco.editor.IEditorDecorationsCollection>()
// Editor state
const [editorLanguage, setEditorLanguage] = useState("plaintext")
const [cursorLine, setCursorLine] = useState(0)
@ -375,6 +382,49 @@ export default function CodeEditor({
})
}, [editorRef])
// handle apply code
const handleApplyCode = useCallback(
(mergedCode: string) => {
if (!editorRef) return
const originalLines = activeFileContent.split("\n")
const mergedLines = mergedCode.split("\n")
const decorations: monaco.editor.IModelDeltaDecoration[] = []
for (
let i = 0;
i < Math.max(originalLines.length, mergedLines.length);
i++
) {
if (originalLines[i] !== mergedLines[i]) {
decorations.push({
range: new monaco.Range(i + 1, 1, i + 1, 1),
options: {
isWholeLine: true,
className:
i < originalLines.length
? "removed-line-decoration"
: "added-line-decoration",
glyphMarginClassName:
i < originalLines.length
? "removed-line-glyph"
: "added-line-glyph",
},
})
}
}
// Update editor content
editorRef.setValue(mergedCode)
// Apply decorations
const newDecorations = editorRef.createDecorationsCollection(decorations)
setMergeDecorationsCollection(newDecorations)
},
[editorRef, activeFileContent]
)
// Generate widget effect
useEffect(() => {
if (generate.show) {
@ -1234,6 +1284,9 @@ export default function CodeEditor({
lastCopiedRangeRef={lastCopiedRangeRef}
files={files}
templateType={sandboxData.type}
handleApplyCode={handleApplyCode}
mergeDecorationsCollection={mergeDecorationsCollection}
setMergeDecorationsCollection={setMergeDecorationsCollection}
/>
</ResizablePanel>
</>