mirror of
https://github.com/cfngc4594/monaco-editor-lsp-next.git
synced 2025-07-04 09:20:53 +00:00
commit
2344748666
@ -157,6 +157,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"WorkspaceEditorHeader": {
|
"WorkspaceEditorHeader": {
|
||||||
|
"ViewToggleButton": {
|
||||||
|
"ShowCodeView": "Show code view",
|
||||||
|
"ShowDiffView": "Show diff view"
|
||||||
|
},
|
||||||
|
"OptimizeButton":{
|
||||||
|
"TooltipContent": "Optimize Code",
|
||||||
|
"Error": "Error occurred while optimizing code, please try again later."
|
||||||
|
},
|
||||||
"LspStatusButton": {
|
"LspStatusButton": {
|
||||||
"TooltipContent": "Language Server"
|
"TooltipContent": "Language Server"
|
||||||
},
|
},
|
||||||
|
@ -157,6 +157,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"WorkspaceEditorHeader": {
|
"WorkspaceEditorHeader": {
|
||||||
|
"ViewToggleButton": {
|
||||||
|
"ShowCodeView": "查看源代码",
|
||||||
|
"ShowDiffView": "查看优化代码"
|
||||||
|
},
|
||||||
|
"OptimizeButton":{
|
||||||
|
"TooltipContent": "优化代码",
|
||||||
|
"Error": "优化代码时出错,请稍后重试。"
|
||||||
|
},
|
||||||
"LspStatusButton": {
|
"LspStatusButton": {
|
||||||
"TooltipContent": "语言服务"
|
"TooltipContent": "语言服务"
|
||||||
},
|
},
|
||||||
|
@ -66,7 +66,9 @@ export const analyzeComplexity = async (
|
|||||||
return validationResult.data;
|
return validationResult.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAnalysis = async (submissionId: string):Promise<CodeAnalysis> => {
|
export const getAnalysis = async (
|
||||||
|
submissionId: string
|
||||||
|
): Promise<CodeAnalysis> => {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
|
|
||||||
if (!session?.user?.id) {
|
if (!session?.user?.id) {
|
||||||
@ -85,3 +87,32 @@ export const getAnalysis = async (submissionId: string):Promise<CodeAnalysis> =>
|
|||||||
|
|
||||||
return analysis;
|
return analysis;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const optimizeCode = async (content: string): Promise<string> => {
|
||||||
|
const model = openai("gpt-4o-mini");
|
||||||
|
|
||||||
|
const prompt = `
|
||||||
|
Optimize the following code snippet for better performance, readability, and maintainability.
|
||||||
|
Provide ONLY the improved code without any explanations, comments, or additional text.
|
||||||
|
|
||||||
|
Code to optimize:
|
||||||
|
\`\`\`
|
||||||
|
${content}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
Respond ONLY with the optimized code. Do not include any other text or markdown formatting like \`\`\`.
|
||||||
|
`;
|
||||||
|
|
||||||
|
const messages: CoreMessage[] = [{ role: "user", content: prompt }];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await generateText({
|
||||||
|
model: model,
|
||||||
|
messages: messages,
|
||||||
|
});
|
||||||
|
return response.text.trim();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error optimizing code:", error);
|
||||||
|
throw new Error("Failed to optimize code");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1,68 +1,127 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
import { DiffEditor } from "@monaco-editor/react";
|
import { DiffEditor } from "@monaco-editor/react";
|
||||||
import { optimizeCode } from "@/app/actions/ai-improve";
|
import { optimizeCode } from "@/app/actions/ai-improve";
|
||||||
import { useMonacoTheme } from "@/hooks/use-monaco-theme";
|
import type { OptimizeCodeInput } from "@/types/ai-improve";
|
||||||
import React, { useState, useEffect, useCallback } from "react";
|
import { CoreEditor } from "./core-editor"; // 引入你刚刚的组件
|
||||||
import { useProblemEditorStore } from "@/stores/problem-editor";
|
// import { Loading } from "@/components/loading";
|
||||||
|
import type { LanguageServerConfig } from "@/generated/client";
|
||||||
|
|
||||||
export const AIEditorWrapper = () => {
|
interface AIEditorWrapperProps {
|
||||||
const {
|
language?: string;
|
||||||
language,
|
value?: string;
|
||||||
value: originalCode,
|
path?: string;
|
||||||
setLoading,
|
problemId?: string;
|
||||||
AIgenerate,
|
languageServerConfigs?: LanguageServerConfig[];
|
||||||
LastOptimizedCode,
|
onChange?: (value: string) => void;
|
||||||
setLastOptimizedCode,
|
className?: string;
|
||||||
} = useProblemEditorStore();
|
}
|
||||||
|
|
||||||
const [optimizedCode, setOptimizedCode] = useState<string>("");
|
export const AIEditorWrapper = ({
|
||||||
const { theme } = useMonacoTheme();
|
language,
|
||||||
|
value,
|
||||||
|
path,
|
||||||
|
problemId,
|
||||||
|
languageServerConfigs,
|
||||||
|
onChange,
|
||||||
|
}: // className,
|
||||||
|
AIEditorWrapperProps) => {
|
||||||
|
const [currentCode, setCurrentCode] = useState(value ?? "");
|
||||||
|
const [optimizedCode, setOptimizedCode] = useState("");
|
||||||
|
const [isOptimizing, setIsOptimizing] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [showDiff, setShowDiff] = useState(false);
|
||||||
|
|
||||||
|
const handleCodeChange = useCallback(
|
||||||
|
(val: string) => {
|
||||||
|
setCurrentCode(val);
|
||||||
|
onChange?.(val);
|
||||||
|
},
|
||||||
|
[onChange]
|
||||||
|
);
|
||||||
|
|
||||||
const handleOptimize = useCallback(async () => {
|
const handleOptimize = useCallback(async () => {
|
||||||
setLoading(true);
|
if (!problemId || !currentCode) return;
|
||||||
try {
|
setIsOptimizing(true);
|
||||||
const res = await optimizeCode({
|
setError(null);
|
||||||
code: originalCode,
|
|
||||||
error: "",
|
|
||||||
problemId: "",
|
|
||||||
});
|
|
||||||
setOptimizedCode(res.optimizedCode);
|
|
||||||
setLastOptimizedCode(res.optimizedCode);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("优化失败", err);
|
|
||||||
setOptimizedCode("// 优化失败,请稍后重试");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [originalCode, setLoading, setLastOptimizedCode]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
try {
|
||||||
if (AIgenerate) {
|
const input: OptimizeCodeInput = {
|
||||||
handleOptimize();
|
code: currentCode,
|
||||||
} else if (LastOptimizedCode) {
|
problemId,
|
||||||
setOptimizedCode(LastOptimizedCode);
|
};
|
||||||
|
const result = await optimizeCode(input);
|
||||||
|
setOptimizedCode(result.optimizedCode);
|
||||||
|
setShowDiff(true);
|
||||||
|
} catch (err) {
|
||||||
|
setError("AI 优化失败,请稍后重试");
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
setIsOptimizing(false);
|
||||||
}
|
}
|
||||||
}, [AIgenerate, LastOptimizedCode, handleOptimize]);
|
}, [currentCode, problemId]);
|
||||||
|
|
||||||
|
const handleApplyOptimized = useCallback(() => {
|
||||||
|
setCurrentCode(optimizedCode);
|
||||||
|
onChange?.(optimizedCode);
|
||||||
|
setShowDiff(false);
|
||||||
|
}, [optimizedCode, onChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-[80vh] flex flex-col gap-4">
|
<div className="flex flex-col h-full w-full">
|
||||||
{optimizedCode && (
|
<div className="flex items-center justify-between p-4">
|
||||||
<div className="flex-1">
|
<button
|
||||||
<DiffEditor
|
onClick={handleOptimize}
|
||||||
language={language}
|
disabled={isOptimizing}
|
||||||
original={originalCode}
|
className="px-4 py-2 bg-primary text-white rounded hover:bg-primary/90"
|
||||||
modified={optimizedCode}
|
>
|
||||||
height="100%"
|
{isOptimizing ? "优化中..." : "AI优化代码"}
|
||||||
theme={theme}
|
</button>
|
||||||
options={{
|
|
||||||
readOnly: true,
|
{showDiff && (
|
||||||
renderSideBySide: true,
|
<div className="space-x-2">
|
||||||
automaticLayout: true,
|
<button
|
||||||
}}
|
onClick={() => setShowDiff(false)}
|
||||||
/>
|
className="px-4 py-2 bg-secondary text-white rounded"
|
||||||
</div>
|
>
|
||||||
|
隐藏对比
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleApplyOptimized}
|
||||||
|
className="px-4 py-2 bg-green-500 text-white rounded"
|
||||||
|
>
|
||||||
|
应用优化结果
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="p-3 bg-red-100 text-red-600 rounded-md">{error}</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div className="flex-grow overflow-hidden">
|
||||||
|
{showDiff ? (
|
||||||
|
<DiffEditor
|
||||||
|
original={currentCode}
|
||||||
|
modified={optimizedCode}
|
||||||
|
language={language}
|
||||||
|
theme="vs-dark"
|
||||||
|
className="h-full w-full"
|
||||||
|
options={{ readOnly: true, minimap: { enabled: false } }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CoreEditor
|
||||||
|
language={language}
|
||||||
|
value={currentCode}
|
||||||
|
path={path}
|
||||||
|
languageServerConfigs={languageServerConfigs}
|
||||||
|
onChange={handleCodeChange}
|
||||||
|
className="h-full w-full"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
70
src/components/core-diff-editor.tsx
Normal file
70
src/components/core-diff-editor.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import type { editor } from "monaco-editor";
|
||||||
|
import { useCallback, useRef } from "react";
|
||||||
|
import { getHighlighter } from "@/lib/shiki";
|
||||||
|
import { Loading } from "@/components/loading";
|
||||||
|
import { shikiToMonaco } from "@shikijs/monaco";
|
||||||
|
import type { Monaco } from "@monaco-editor/react";
|
||||||
|
import { DEFAULT_EDITOR_OPTIONS } from "@/config/editor";
|
||||||
|
import { useMonacoTheme } from "@/hooks/use-monaco-theme";
|
||||||
|
|
||||||
|
const MonacoEditor = dynamic(
|
||||||
|
async () => {
|
||||||
|
const react = await import("@monaco-editor/react");
|
||||||
|
|
||||||
|
return react.DiffEditor;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ssr: false,
|
||||||
|
loading: () => <Loading />,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
interface CoreDiffEditorProps {
|
||||||
|
language?: string;
|
||||||
|
original?: string;
|
||||||
|
modified?: string;
|
||||||
|
onEditorReady?: (editor: editor.IStandaloneDiffEditor) => void;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CoreDiffEditor = ({
|
||||||
|
language,
|
||||||
|
original,
|
||||||
|
modified,
|
||||||
|
onEditorReady,
|
||||||
|
className,
|
||||||
|
}: CoreDiffEditorProps) => {
|
||||||
|
const { theme } = useMonacoTheme();
|
||||||
|
|
||||||
|
const editorRef = useRef<editor.IStandaloneDiffEditor | null>(null);
|
||||||
|
|
||||||
|
const handleBeforeMount = useCallback((monaco: Monaco) => {
|
||||||
|
const highlighter = getHighlighter();
|
||||||
|
shikiToMonaco(highlighter, monaco);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleOnMount = useCallback(
|
||||||
|
(editor: editor.IStandaloneDiffEditor) => {
|
||||||
|
editorRef.current = editor;
|
||||||
|
onEditorReady?.(editor);
|
||||||
|
},
|
||||||
|
[onEditorReady]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MonacoEditor
|
||||||
|
theme={theme}
|
||||||
|
language={language}
|
||||||
|
original={original}
|
||||||
|
modified={modified}
|
||||||
|
beforeMount={handleBeforeMount}
|
||||||
|
onMount={handleOnMount}
|
||||||
|
options={{ ...DEFAULT_EDITOR_OPTIONS, readOnly: true }}
|
||||||
|
loading={<Loading />}
|
||||||
|
className={className}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { CoreEditor } from "@/components/core-editor";
|
import { CoreEditor } from "@/components/core-editor";
|
||||||
|
import { CoreDiffEditor } from "@/components/core-diff-editor";
|
||||||
import { useProblemEditorStore } from "@/stores/problem-editor";
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
import { AIEditorWrapper } from "@/components/ai-optimized-editor";
|
|
||||||
import type { LanguageServerConfig, Template } from "@/generated/client";
|
import type { LanguageServerConfig, Template } from "@/generated/client";
|
||||||
|
|
||||||
interface ProblemEditorProps {
|
interface ProblemEditorProps {
|
||||||
@ -20,45 +20,53 @@ export const ProblemEditor = ({
|
|||||||
const {
|
const {
|
||||||
language,
|
language,
|
||||||
value,
|
value,
|
||||||
|
optimizedCode,
|
||||||
path,
|
path,
|
||||||
setProblem,
|
setProblem,
|
||||||
setValue,
|
setValue,
|
||||||
setEditor,
|
setEditor,
|
||||||
|
setDiffEditor,
|
||||||
setLspWebSocket,
|
setLspWebSocket,
|
||||||
setMarkers,
|
setMarkers,
|
||||||
useAIEditor,
|
showDiffView,
|
||||||
// setUseAIEditor
|
|
||||||
} = useProblemEditorStore();
|
} = useProblemEditorStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProblem(problemId, templates);
|
setProblem(problemId, templates);
|
||||||
}, [problemId, setProblem, templates]);
|
}, [problemId, setProblem, templates]);
|
||||||
|
|
||||||
return (
|
if (!optimizedCode) {
|
||||||
<div className="w-full h-[85vh] relative">
|
return (
|
||||||
{!useAIEditor ? (
|
<CoreEditor
|
||||||
<>
|
language={language}
|
||||||
{/*<button*/}
|
value={value}
|
||||||
{/* className="absolute right-4 top-4 bg-blue-600 text-white px-3 py-1 rounded z-10"*/}
|
path={path}
|
||||||
{/* onClick={() => setUseAIEditor(true)}*/}
|
languageServerConfigs={languageServerConfigs}
|
||||||
{/*>*/}
|
onEditorReady={setEditor}
|
||||||
{/* AI 优化代码*/}
|
onLspWebSocketReady={setLspWebSocket}
|
||||||
{/*</button>*/}
|
onMarkersReady={setMarkers}
|
||||||
<CoreEditor
|
onChange={setValue}
|
||||||
language={language}
|
/>
|
||||||
value={value}
|
);
|
||||||
path={path}
|
}
|
||||||
languageServerConfigs={languageServerConfigs}
|
|
||||||
onEditorReady={setEditor}
|
return showDiffView ? (
|
||||||
onLspWebSocketReady={setLspWebSocket}
|
<CoreDiffEditor
|
||||||
onMarkersReady={setMarkers}
|
language={language}
|
||||||
onChange={setValue}
|
original={value}
|
||||||
className="h-[80vh] w-full"
|
modified={optimizedCode}
|
||||||
/>
|
onEditorReady={setDiffEditor}
|
||||||
</>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<AIEditorWrapper />
|
<CoreEditor
|
||||||
)}
|
language={language}
|
||||||
</div>
|
value={optimizedCode}
|
||||||
|
path={path}
|
||||||
|
languageServerConfigs={languageServerConfigs}
|
||||||
|
onEditorReady={setEditor}
|
||||||
|
onLspWebSocketReady={setLspWebSocket}
|
||||||
|
onMarkersReady={setMarkers}
|
||||||
|
onChange={setValue}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { TooltipButton } from "@/components/tooltip-button";
|
|
||||||
import { useProblemEditorStore } from "@/stores/problem-editor";
|
|
||||||
import { ArrowLeftRight, LoaderCircleIcon, Undo2Icon } from "lucide-react";
|
|
||||||
|
|
||||||
export const AIDisplayButton = () => {
|
|
||||||
const { useAIEditor, setUseAIEditor, setAIgenerate, loading } =
|
|
||||||
useProblemEditorStore();
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
setAIgenerate(false);
|
|
||||||
if (!loading) {
|
|
||||||
setUseAIEditor(!useAIEditor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const tooltipContent = loading
|
|
||||||
? "AI 正在优化中…"
|
|
||||||
: useAIEditor
|
|
||||||
? "返回原始编辑器"
|
|
||||||
: "查看 AI 优化代码";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TooltipButton
|
|
||||||
tooltipContent={tooltipContent}
|
|
||||||
onClick={handleClick}
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<LoaderCircleIcon
|
|
||||||
className="opacity-60 animate-spin"
|
|
||||||
size={16}
|
|
||||||
strokeWidth={2}
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
) : useAIEditor ? (
|
|
||||||
<Undo2Icon size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
) : (
|
|
||||||
<ArrowLeftRight size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
)}
|
|
||||||
</TooltipButton>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,42 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { Wand2Icon } from "lucide-react";
|
|
||||||
import { TooltipButton } from "@/components/tooltip-button";
|
|
||||||
//import { LoaderCircleIcon, Undo2Icon } from "lucide-react";
|
|
||||||
import { useProblemEditorStore } from "@/stores/problem-editor";
|
|
||||||
|
|
||||||
export const AIOptimizeButton = () => {
|
|
||||||
const { useAIEditor, setUseAIEditor, setAIgenerate, loading } =
|
|
||||||
useProblemEditorStore();
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
setAIgenerate(true);
|
|
||||||
if (!loading) {
|
|
||||||
setUseAIEditor(!useAIEditor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ? "AI 正在优化中…"
|
|
||||||
// : useAIEditor
|
|
||||||
// ? "返回原始编辑器"
|
|
||||||
// : "使用 AI 优化代码";
|
|
||||||
|
|
||||||
const tooltipContent = "使用 AI 优化代码"; // 仅保留默认提示内容
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TooltipButton
|
|
||||||
tooltipContent={tooltipContent}
|
|
||||||
onClick={handleClick}
|
|
||||||
disabled={loading || useAIEditor}
|
|
||||||
>
|
|
||||||
{loading ? // className="opacity-60 animate-spin" // <LoaderCircleIcon
|
|
||||||
// size={16}
|
|
||||||
// strokeWidth={2}
|
|
||||||
// aria-hidden="true"
|
|
||||||
// />
|
|
||||||
null : useAIEditor ? null : ( // <Undo2Icon size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
<Wand2Icon size={16} strokeWidth={2} aria-hidden="true" />
|
|
||||||
)}
|
|
||||||
</TooltipButton>
|
|
||||||
);
|
|
||||||
};
|
|
@ -0,0 +1,52 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { optimizeCode } from "@/app/actions/analyze";
|
||||||
|
import { LoaderCircleIcon, Wand2Icon } from "lucide-react";
|
||||||
|
import { TooltipButton } from "@/components/tooltip-button";
|
||||||
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
|
import { useProblemEditorActions } from "@/features/problems/code/hooks/use-problem-editor-actions";
|
||||||
|
|
||||||
|
export const OptimizeButton = () => {
|
||||||
|
const t = useTranslations("WorkspaceEditorHeader.OptimizeButton");
|
||||||
|
const { value, setOptimizedCode } = useProblemEditorStore();
|
||||||
|
const { canExecute } = useProblemEditorActions();
|
||||||
|
// const [error, setError] = useState<string | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const handleClick = async () => {
|
||||||
|
// setError(null);
|
||||||
|
setIsLoading(true);
|
||||||
|
setOptimizedCode("");
|
||||||
|
try {
|
||||||
|
const optimizedCode = await optimizeCode(value);
|
||||||
|
setOptimizedCode(optimizedCode);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error analyzing complexity:", error);
|
||||||
|
setOptimizedCode("");
|
||||||
|
// setError(t("Error"));
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TooltipButton
|
||||||
|
tooltipContent={t("TooltipContent")}
|
||||||
|
onClick={handleClick}
|
||||||
|
disabled={!canExecute || isLoading}
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<LoaderCircleIcon
|
||||||
|
className="opacity-60 animate-spin"
|
||||||
|
size={16}
|
||||||
|
strokeWidth={2}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Wand2Icon size={16} strokeWidth={2} aria-hidden="true" />
|
||||||
|
)}
|
||||||
|
</TooltipButton>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { CodeXmlIcon, GitCompareIcon } from "lucide-react";
|
||||||
|
import { TooltipButton } from "@/components/tooltip-button";
|
||||||
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
|
|
||||||
|
export const ViewToggleButton = () => {
|
||||||
|
const t = useTranslations("WorkspaceEditorHeader.ViewToggleButton");
|
||||||
|
const { showDiffView, toggleView } = useProblemEditorStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TooltipButton
|
||||||
|
tooltipContent={showDiffView ? t("ShowCodeView") : t("ShowDiffView")}
|
||||||
|
onClick={toggleView}
|
||||||
|
>
|
||||||
|
{showDiffView ? (
|
||||||
|
<CodeXmlIcon size={16} strokeWidth={2} aria-hidden="true" />
|
||||||
|
) : (
|
||||||
|
<GitCompareIcon size={16} strokeWidth={2} aria-hidden="true" />
|
||||||
|
)}
|
||||||
|
</TooltipButton>
|
||||||
|
);
|
||||||
|
};
|
@ -1,3 +1,5 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import {
|
import {
|
||||||
CopyButton,
|
CopyButton,
|
||||||
@ -7,16 +9,19 @@ import {
|
|||||||
ResetButton,
|
ResetButton,
|
||||||
UndoButton,
|
UndoButton,
|
||||||
} from "@/features/problems/code/components/toolbar";
|
} from "@/features/problems/code/components/toolbar";
|
||||||
import { AnalyzeButton } from "./actions/analyze-button";
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
import { LspConnectionIndicator } from "./controls/lsp-connection-indicator";
|
import { AnalyzeButton } from "@/features/problems/code/components/toolbar/actions/analyze-button";
|
||||||
import { AIDisplayButton } from "@/features/problems/code/components/toolbar/actions/AIDisplayButton";
|
import { OptimizeButton } from "@/features/problems/code/components/toolbar/actions/optimize-button";
|
||||||
import { AIOptimizeButton } from "@/features/problems/code/components/toolbar/actions/AIOptimizeButton";
|
import { ViewToggleButton } from "@/features/problems/code/components/toolbar/actions/view-toggle-button";
|
||||||
|
import { LspConnectionIndicator } from "@/features/problems/code/components/toolbar/controls/lsp-connection-indicator";
|
||||||
|
|
||||||
interface CodeToolbarProps {
|
interface CodeToolbarProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodeToolbar = async ({ className }: CodeToolbarProps) => {
|
export const CodeToolbar = ({ className }: CodeToolbarProps) => {
|
||||||
|
const { optimizedCode } = useProblemEditorStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className={cn("relative flex h-8 flex-none items-center", className)}
|
className={cn("relative flex h-8 flex-none items-center", className)}
|
||||||
@ -27,8 +32,8 @@ export const CodeToolbar = async ({ className }: CodeToolbarProps) => {
|
|||||||
<LspConnectionIndicator />
|
<LspConnectionIndicator />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<AIOptimizeButton />
|
{optimizedCode && <ViewToggleButton />}
|
||||||
<AIDisplayButton />
|
<OptimizeButton />
|
||||||
<AnalyzeButton />
|
<AnalyzeButton />
|
||||||
<ResetButton />
|
<ResetButton />
|
||||||
<UndoButton />
|
<UndoButton />
|
||||||
|
@ -12,28 +12,26 @@ type ProblemEditorState = {
|
|||||||
problem: Problem | null;
|
problem: Problem | null;
|
||||||
language: Language;
|
language: Language;
|
||||||
value: string;
|
value: string;
|
||||||
|
optimizedCode: string;
|
||||||
path: string;
|
path: string;
|
||||||
editor: editor.IStandaloneCodeEditor | null;
|
editor: editor.IStandaloneCodeEditor | null;
|
||||||
|
diffEditor: editor.IStandaloneDiffEditor | null;
|
||||||
lspWebSocket: WebSocket | null;
|
lspWebSocket: WebSocket | null;
|
||||||
markers: editor.IMarker[];
|
markers: editor.IMarker[];
|
||||||
useAIEditor: boolean;
|
showDiffView: boolean;
|
||||||
loading: boolean;
|
|
||||||
AIgenerate: boolean;
|
|
||||||
LastOptimizedCode: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProblemEditorAction = {
|
type ProblemEditorAction = {
|
||||||
setProblem: (problemId: string, templates: Template[]) => void;
|
setProblem: (problemId: string, templates: Template[]) => void;
|
||||||
setLanguage: (language: Language) => void;
|
setLanguage: (language: Language) => void;
|
||||||
setValue: (value: string) => void;
|
setValue: (value: string) => void;
|
||||||
|
setOptimizedCode: (value: string) => void;
|
||||||
setPath: (path: string) => void;
|
setPath: (path: string) => void;
|
||||||
setEditor: (editor: editor.IStandaloneCodeEditor) => void;
|
setEditor: (editor: editor.IStandaloneCodeEditor) => void;
|
||||||
|
setDiffEditor: (diffEditor: editor.IStandaloneDiffEditor) => void;
|
||||||
setLspWebSocket: (lspWebSocket: WebSocket) => void;
|
setLspWebSocket: (lspWebSocket: WebSocket) => void;
|
||||||
setMarkers: (markers: editor.IMarker[]) => void;
|
setMarkers: (markers: editor.IMarker[]) => void;
|
||||||
setUseAIEditor: (flag: boolean) => void;
|
toggleView: () => void;
|
||||||
setLoading: (flag: boolean) => void;
|
|
||||||
setAIgenerate: (flag: boolean) => void;
|
|
||||||
setLastOptimizedCode: (code: string) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProblemEditorStore = ProblemEditorState & ProblemEditorAction;
|
type ProblemEditorStore = ProblemEditorState & ProblemEditorAction;
|
||||||
@ -42,18 +40,13 @@ export const useProblemEditorStore = create<ProblemEditorStore>((set, get) => ({
|
|||||||
problem: null,
|
problem: null,
|
||||||
language: Language.c,
|
language: Language.c,
|
||||||
value: "",
|
value: "",
|
||||||
|
optimizedCode: "",
|
||||||
path: "",
|
path: "",
|
||||||
editor: null,
|
editor: null,
|
||||||
|
diffEditor: null,
|
||||||
lspWebSocket: null,
|
lspWebSocket: null,
|
||||||
markers: [],
|
markers: [],
|
||||||
useAIEditor: false,
|
showDiffView: false,
|
||||||
loading: false,
|
|
||||||
AIgenerate: false,
|
|
||||||
LastOptimizedCode: "",
|
|
||||||
setLastOptimizedCode: (code) => set({ LastOptimizedCode: code }),
|
|
||||||
setAIgenerate: (flag) => set({ AIgenerate: flag }),
|
|
||||||
setLoading: (loading) => set({ loading }),
|
|
||||||
setUseAIEditor: (loading) => set({ useAIEditor: loading }),
|
|
||||||
setProblem: (problemId, templates) => {
|
setProblem: (problemId, templates) => {
|
||||||
const language = getLanguage(problemId);
|
const language = getLanguage(problemId);
|
||||||
const value = getValue(problemId, language, templates);
|
const value = getValue(problemId, language, templates);
|
||||||
@ -80,10 +73,13 @@ export const useProblemEditorStore = create<ProblemEditorStore>((set, get) => ({
|
|||||||
}
|
}
|
||||||
set({ value });
|
set({ value });
|
||||||
},
|
},
|
||||||
|
setOptimizedCode: (optimizedCode) => set({ optimizedCode }),
|
||||||
setPath: (path) => set({ path }),
|
setPath: (path) => set({ path }),
|
||||||
setEditor: (editor) => set({ editor }),
|
setEditor: (editor) => set({ editor }),
|
||||||
|
setDiffEditor: (diffEditor) => set({ diffEditor }),
|
||||||
setLspWebSocket: (lspWebSocket) => set({ lspWebSocket }),
|
setLspWebSocket: (lspWebSocket) => set({ lspWebSocket }),
|
||||||
setMarkers: (markers) => set({ markers }),
|
setMarkers: (markers) => set({ markers }),
|
||||||
|
toggleView: () => set((state) => ({ showDiffView: !state.showDiffView })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const getStoredItem = <T extends string>(
|
const getStoredItem = <T extends string>(
|
||||||
|
Loading…
Reference in New Issue
Block a user