Skip to content

Commit

Permalink
format update
Browse files Browse the repository at this point in the history
  • Loading branch information
imrishabh18 committed Oct 29, 2024
1 parent 0301c1c commit bfe725a
Showing 1 changed file with 128 additions and 107 deletions.
235 changes: 128 additions & 107 deletions src/components/CodeEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React, { useEffect, useRef, useState } from "react"
import { Button } from "@/components/ui/button"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { useToast } from "@/hooks/use-toast"
import { autocompletion } from "@codemirror/autocomplete"
import { indentWithTab } from "@codemirror/commands"
Expand All @@ -11,8 +17,17 @@ import { Decoration, hoverTooltip, keymap } from "@codemirror/view"
import { getImportsFromCode } from "@tscircuit/prompt-benchmarks/code-runner-utils"
import { setupTypeAcquisition } from "@typescript/ata"
import type { ATABootstrapConfig } from "@typescript/ata"
import { createSystem, createVirtualTypeScriptEnvironment } from "@typescript/vfs"
import { tsAutocomplete, tsFacet, tsHover, tsLinter, tsSync } from "@valtown/codemirror-ts"
import {
createSystem,
createVirtualTypeScriptEnvironment,
} from "@typescript/vfs"
import {
tsAutocomplete,
tsFacet,
tsHover,
tsLinter,
tsSync,
} from "@valtown/codemirror-ts"
import { EditorView, basicSetup } from "codemirror"
import ts from "typescript"
import { useImportSnippetDialog } from "./dialogs/import-snippet-dialog"
Expand All @@ -33,7 +48,8 @@ export const CodeEditor = ({
const editorRef = useRef<HTMLDivElement>(null)
const viewRef = useRef<EditorView | null>(null)
const ataRef = useRef<ReturnType<typeof setupTypeAcquisition> | null>(null)
const { Dialog: ImportSnippetDialog, openDialog: openImportDialog } = useImportSnippetDialog()
const { Dialog: ImportSnippetDialog, openDialog: openImportDialog } =
useImportSnippetDialog()
const { toast } = useToast()

const [files, setFiles] = useState<Record<string, string>>({
Expand All @@ -44,9 +60,9 @@ export const CodeEditor = ({

useEffect(() => {
if (code !== files["index.tsx"]) {
setFiles(prev => ({
setFiles((prev) => ({
...prev,
"index.tsx": code
"index.tsx": code,
}))
}
}, [code])
Expand Down Expand Up @@ -123,15 +139,17 @@ export const CodeEditor = ({
// Set up base extensions
const baseExtensions = [
basicSetup,
currentFile.endsWith('.json') ? json() : javascript({ typescript: true, jsx: true }),
currentFile.endsWith(".json")
? json()
: javascript({ typescript: true, jsx: true }),
keymap.of([indentWithTab]),
EditorState.readOnly.of(readOnly),
EditorView.updateListener.of((update) => {
if (update.docChanged) {
const newContent = update.state.doc.toString()
setFiles(prev => ({
setFiles((prev) => ({
...prev,
[currentFile]: newContent
[currentFile]: newContent,
}))
onCodeChange(newContent, currentFile)

Expand All @@ -140,108 +158,114 @@ export const CodeEditor = ({
currentFile,
true,
)
const indexDts = outputFiles.find(file => file.name === "index.d.ts")
const indexDts = outputFiles.find(
(file) => file.name === "index.d.ts",
)
if (indexDts?.text && onDtsChange) {
onDtsChange(indexDts.text)
}
}
}
})
}),
]

// Add TypeScript-specific extensions and handlers
const tsExtensions = currentFile.endsWith('.tsx') || currentFile.endsWith('.ts')
? [
tsFacet.of({ env, path: currentFile }),
tsSync(),
tsLinter(),
autocompletion({ override: [tsAutocomplete()] }),
tsHover(),
hoverTooltip((view, pos, side) => {
const { from, to, text } = view.state.doc.lineAt(pos)
const line = text.slice(from, to)
const match = line.match(/@tsci\/[\w.]+/)
if (match) {
const importName = match[0]
const start = line.indexOf(importName)
const end = start + importName.length
if (pos >= from + start && pos <= from + end) {
return {
pos: from + start,
end: from + end,
above: true,
create() {
const dom = document.createElement("div")
dom.textContent = "Ctrl/Cmd+Click to open snippet"
return { dom }
},
const tsExtensions =
currentFile.endsWith(".tsx") || currentFile.endsWith(".ts")
? [
tsFacet.of({ env, path: currentFile }),
tsSync(),
tsLinter(),
autocompletion({ override: [tsAutocomplete()] }),
tsHover(),
hoverTooltip((view, pos, side) => {
const { from, to, text } = view.state.doc.lineAt(pos)
const line = text.slice(from, to)
const match = line.match(/@tsci\/[\w.]+/)
if (match) {
const importName = match[0]
const start = line.indexOf(importName)
const end = start + importName.length
if (pos >= from + start && pos <= from + end) {
return {
pos: from + start,
end: from + end,
above: true,
create() {
const dom = document.createElement("div")
dom.textContent = "Ctrl/Cmd+Click to open snippet"
return { dom }
},
}
}
}
}
return null
}),
EditorView.domEventHandlers({
click: (event, view) => {
if (!event.ctrlKey && !event.metaKey) return false
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY })
if (pos) {
const { from, to, text } = view.state.doc.lineAt(pos)
const line = text.slice(from, to)
const match = line.match(/@tsci\/[\w.]+/)
if (match) {
const importName = match[0]
const start = line.indexOf(importName)
const end = start + importName.length
if (pos >= from + start && pos <= from + end) {
handleImportClick(importName)
return true
return null
}),
EditorView.domEventHandlers({
click: (event, view) => {
if (!event.ctrlKey && !event.metaKey) return false
const pos = view.posAtCoords({
x: event.clientX,
y: event.clientY,
})
if (pos) {
const { from, to, text } = view.state.doc.lineAt(pos)
const line = text.slice(from, to)
const match = line.match(/@tsci\/[\w.]+/)
if (match) {
const importName = match[0]
const start = line.indexOf(importName)
const end = start + importName.length
if (pos >= from + start && pos <= from + end) {
handleImportClick(importName)
return true
}
}
}
}
return false
},
}),
EditorView.theme({
".cm-content .cm-underline": {
textDecoration: "underline",
textDecorationColor: "rgba(0, 0, 255, 0.3)",
cursor: "pointer",
},
}),
EditorView.decorations.of(view => {
const decorations = []
for (const { from, to } of view.visibleRanges) {
for (let pos = from; pos < to;) {
const line = view.state.doc.lineAt(pos)
const lineText = line.text
const matches = lineText.matchAll(/@tsci\/[\w.]+/g)
for (const match of matches) {
if (match.index !== undefined) {
const start = line.from + match.index
const end = start + match[0].length
decorations.push(
Decoration.mark({
class: "cm-underline"
}).range(start, end)
)
return false
},
}),
EditorView.theme({
".cm-content .cm-underline": {
textDecoration: "underline",
textDecorationColor: "rgba(0, 0, 255, 0.3)",
cursor: "pointer",
},
}),
EditorView.decorations.of((view) => {
const decorations = []
for (const { from, to } of view.visibleRanges) {
for (let pos = from; pos < to; ) {
const line = view.state.doc.lineAt(pos)
const lineText = line.text
const matches = lineText.matchAll(/@tsci\/[\w.]+/g)
for (const match of matches) {
if (match.index !== undefined) {
const start = line.from + match.index
const end = start + match[0].length
decorations.push(
Decoration.mark({
class: "cm-underline",
}).range(start, end),
)
}
}
pos = line.to + 1
}
pos = line.to + 1
}
}
return Decoration.set(decorations)
})
]
: []
return Decoration.set(decorations)
}),
]
: []

const state = EditorState.create({
doc: files[currentFile],
extensions: [...baseExtensions, ...tsExtensions]
extensions: [...baseExtensions, ...tsExtensions],
})

const view = new EditorView({
state,
parent: editorRef.current
parent: editorRef.current,
})

viewRef.current = view
Expand All @@ -267,7 +291,7 @@ ${files["index.tsx"]}
const currentContent = files[currentFile] || ""
if (state.doc.toString() !== currentContent) {
viewRef.current.dispatch({
changes: { from: 0, to: state.doc.length, insert: currentContent }
changes: { from: 0, to: state.doc.length, insert: currentContent },
})
}
}
Expand All @@ -291,9 +315,9 @@ ${files["index.tsx"]}
}

const updateFileContent = (filename: string, newContent: string) => {
setFiles(prev => ({
setFiles((prev) => ({
...prev,
[filename]: newContent
[filename]: newContent,
}))

if (filename === "index.tsx") {
Expand All @@ -305,8 +329,8 @@ ${files["index.tsx"]}
changes: {
from: 0,
to: viewRef.current.state.doc.length,
insert: newContent
}
insert: newContent,
},
})
}
}
Expand Down Expand Up @@ -339,15 +363,20 @@ ${files["index.tsx"]}
console.error("Formatting error:", error)
toast({
title: "Formatting error",
description: error instanceof Error ? error.message : "Failed to format the code. Please check for syntax errors.",
description:
error instanceof Error
? error.message
: "Failed to format the code. Please check for syntax errors.",
variant: "destructive",
})
}
}

if (isStreaming) {
return (
<div className="font-mono whitespace-pre-wrap text-xs">{files[currentFile]}</div>
<div className="font-mono whitespace-pre-wrap text-xs">
{files[currentFile]}
</div>
)
}

Expand All @@ -367,18 +396,10 @@ ${files["index.tsx"]}
</SelectContent>
</Select>
<div className="flex items-center gap-2 px-2 py-1 ml-auto">
<Button
size="sm"
variant="ghost"
onClick={() => openImportDialog()}
>
<Button size="sm" variant="ghost" onClick={() => openImportDialog()}>
Import
</Button>
<Button
size="sm"
variant="ghost"
onClick={formatCurrentFile}
>
<Button size="sm" variant="ghost" onClick={formatCurrentFile}>
Format
</Button>
</div>
Expand All @@ -392,4 +413,4 @@ ${files["index.tsx"]}
/>
</div>
)
}
}

0 comments on commit bfe725a

Please sign in to comment.