|
1 | 1 | "use client"; |
2 | 2 |
|
3 | | -import { lazy, Suspense, useEffect, useState } from "react"; |
| 3 | +import { lazy, Suspense, useEffect, useMemo, useState } from "react"; |
4 | 4 | import clsx from "clsx"; |
5 | 5 | import { useChangeTheme } from "@/themeToggle"; |
6 | 6 | import { useEmbedContext } from "./embedContext"; |
@@ -41,7 +41,59 @@ interface EditorProps { |
41 | 41 | } |
42 | 42 | export function EditorComponent(props: EditorProps) { |
43 | 43 | const theme = useChangeTheme(); |
44 | | - const { files, writeFile } = useEmbedContext(); |
| 44 | + const { files, writeFile, diagnostics } = useEmbedContext(); |
| 45 | + const fileDiagnostics = useMemo( |
| 46 | + () => diagnostics[props.filename] ?? [], |
| 47 | + [diagnostics, props.filename] |
| 48 | + ); |
| 49 | + |
| 50 | + const annotations = useMemo(() => { |
| 51 | + return fileDiagnostics.map((diag) => ({ |
| 52 | + row: Math.max(0, diag.startLineNumber - 1), |
| 53 | + column: Math.max(0, (diag.startColumn ?? 1) - 1), |
| 54 | + text: diag.message, |
| 55 | + type: diag.severity ?? "error", // "error" | "warning" | "info" |
| 56 | + })); |
| 57 | + }, [fileDiagnostics]); |
| 58 | + |
| 59 | + const markers = useMemo(() => { |
| 60 | + return fileDiagnostics.map((diag) => { |
| 61 | + const startRow = Math.max(0, diag.startLineNumber - 1); |
| 62 | + const endRow = diag.endLineNumber |
| 63 | + ? Math.max(0, diag.endLineNumber - 1) |
| 64 | + : startRow; |
| 65 | + const startCol = |
| 66 | + diag.startColumn !== undefined ? Math.max(0, diag.startColumn - 1) : 0; |
| 67 | + const endCol = |
| 68 | + diag.endColumn !== undefined |
| 69 | + ? Math.max(0, diag.endColumn - 1) |
| 70 | + : Number.MAX_SAFE_INTEGER; |
| 71 | + |
| 72 | + const isError = (diag.severity ?? "error") === "error"; |
| 73 | + const isWarning = diag.severity === "warning"; |
| 74 | + const className = isError |
| 75 | + ? "ace_error-marker" |
| 76 | + : isWarning |
| 77 | + ? "ace_warning-marker" |
| 78 | + : "ace_info-marker"; |
| 79 | + |
| 80 | + return { |
| 81 | + startRow, |
| 82 | + startCol, |
| 83 | + endRow, |
| 84 | + endCol, |
| 85 | + className, |
| 86 | + type: |
| 87 | + diag.startColumn !== undefined && |
| 88 | + diag.endColumn !== undefined && |
| 89 | + startRow === endRow |
| 90 | + ? ("text" as const) |
| 91 | + : ("fullLine" as const), |
| 92 | + inFront: false, |
| 93 | + }; |
| 94 | + }); |
| 95 | + }, [fileDiagnostics]); |
| 96 | + |
45 | 97 | const code = files[props.filename] || props.initContent; |
46 | 98 | useEffect(() => { |
47 | 99 | if (!files[props.filename] && props.initContent) { |
@@ -202,6 +254,8 @@ export function EditorComponent(props: EditorProps) { |
202 | 254 | value={code} |
203 | 255 | onChange={(code: string) => writeFile({ [props.filename]: code })} |
204 | 256 | setOptions={{ useWorker: false }} |
| 257 | + annotations={annotations} |
| 258 | + markers={markers} |
205 | 259 | /> |
206 | 260 | </Suspense> |
207 | 261 | ) : ( |
|
0 commit comments