TCP 서버 모드 추가

This commit is contained in:
현성필
2025-01-21 13:19:21 +09:00
parent e23684d833
commit cb9201ddd2
106 changed files with 17710 additions and 0 deletions
@@ -0,0 +1,162 @@
import React, { useEffect, useRef, memo } from 'react';
import * as monaco from 'monaco-editor';
const MonacoEditor = memo(({
id,
value = '',
language = 'javascript',
readOnly = false,
height = '64',
onChange = () => {}
}) => {
const editorRef = useRef(null);
const containerRef = useRef(null);
const subscriptionRef = useRef(null);
// Configure editor options based on language
const getEditorOptions = (lang) => {
const baseOptions = {
automaticLayout: true,
theme: 'vs-light',
minimap: { enabled: false },
readOnly,
scrollBeyondLastLine: false,
fontSize: 14,
lineHeight: 21,
padding: { top: 8, bottom: 8 },
tabSize: 2,
scrollbar: {
vertical: 'auto',
horizontal: 'auto'
}
};
// Language-specific options
switch (lang) {
case 'json':
return {
...baseOptions,
formatOnPaste: true,
formatOnType: true,
autoClosingBrackets: 'always',
autoClosingQuotes: 'always',
bracketPairColorization: { enabled: true }
};
case 'xml':
return {
...baseOptions,
formatOnType: true,
autoClosingTags: true,
autoClosingBrackets: 'always',
autoClosingQuotes: 'always'
};
default:
return baseOptions;
}
};
// Initialize or update editor
const setupEditor = () => {
if (!containerRef.current) return;
// Dispose existing editor if it exists
if (editorRef.current) {
editorRef.current.dispose();
}
// Create new editor with language-specific options
const options = getEditorOptions(language);
editorRef.current = monaco.editor.create(containerRef.current, {
value,
language,
...options
});
// Set up change event handler
if (subscriptionRef.current) {
subscriptionRef.current.dispose();
}
subscriptionRef.current = editorRef.current.onDidChangeModelContent(() => {
const newValue = editorRef.current.getValue();
onChange(newValue);
});
// Format document if it's JSON
if (language === 'json' && value) {
try {
const modelUri = monaco.Uri.parse(`inmemory://model-${id}.json`);
const model = monaco.editor.createModel(value, 'json', modelUri);
setTimeout(() => {
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
allowComments: false,
schemas: []
});
editorRef.current.setModel(model);
}, 100);
} catch (e) {
console.warn('Failed to format JSON:', e);
}
}
};
// Initial setup
useEffect(() => {
setupEditor();
// Set up resize observer
const resizeObserver = new ResizeObserver(() => {
if (editorRef.current) {
editorRef.current.layout();
}
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
// Cleanup
return () => {
resizeObserver.disconnect();
if (subscriptionRef.current) {
subscriptionRef.current.dispose();
}
if (editorRef.current) {
editorRef.current.dispose();
}
};
}, [language]); // Reinitialize when language changes
// Update value if it changes externally
useEffect(() => {
if (editorRef.current && value !== editorRef.current.getValue()) {
editorRef.current.setValue(value);
// Add formatting for JSON
if (language === 'json' && value) {
try {
const action = editorRef.current.getAction('editor.action.formatDocument');
if (action) {
action.run();
}
} catch (e) {
console.warn('Failed to format JSON:', e);
}
}
}
}, [value, language]);
return (
<div
id={id}
ref={containerRef}
className={`h-${height} border mt-2`}
style={{ minHeight: '100px' }}
/>
);
});
MonacoEditor.displayName = 'MonacoEditor';
export default MonacoEditor;