File size: 4,344 Bytes
c2c8c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { useRef, useCallback, useEffect } from 'react';
import Editor, { OnMount, OnChange } from '@monaco-editor/react';
import { useEditorStore } from '@/stores/editorStore';
import { useSettingsStore } from '@/stores/settingsStore';
import { useCodeCompletion } from '@/hooks/useCodeCompletion';

interface CodeEditorProps {
  filePath: string;
  language: string;
}

export default function CodeEditor({ filePath, language }: CodeEditorProps) {
  const content = useEditorStore((s) => s.openFiles[filePath]?.content || '');
  const updateContent = useEditorStore((s) => s.updateContent);
  const setCursorPosition = useEditorStore((s) => s.setCursorPosition);
  const fontSize = useSettingsStore((s) => s.fontSize);
  const tabSize = useSettingsStore((s) => s.tabSize);
  const wordWrap = useSettingsStore((s) => s.wordWrap);
  const minimap = useSettingsStore((s) => s.minimap);
  const { requestCompletion, dismissCompletion } = useCodeCompletion();
  const editorRef = useRef<any>(null);

  const handleMount: OnMount = (editor, monaco) => {
    editorRef.current = editor;

    // Define custom theme
    monaco.editor.defineTheme('glmpilot-dark', {
      base: 'vs-dark',
      inherit: true,
      rules: [
        { token: 'comment', foreground: '6a737d', fontStyle: 'italic' },
        { token: 'keyword', foreground: 'c792ea' },
        { token: 'string', foreground: 'c3e88d' },
        { token: 'number', foreground: 'f78c6c' },
        { token: 'type', foreground: 'ffcb6b' },
        { token: 'function', foreground: '82aaff' },
      ],
      colors: {
        'editor.background': '#080810',
        'editor.foreground': '#e8e8e8',
        'editorLineNumber.foreground': '#4a4a5a',
        'editor.selectionBackground': '#81f08433',
        'editorCursor.foreground': '#81f084',
        'editor.lineHighlightBackground': '#0f0f1a',
        'editorIndentGuide.background': '#1a1a2a',
        'editorWidget.background': '#121220',
        'editorSuggestWidget.background': '#121220',
        'editorSuggestWidget.border': '#2a2a3a',
        'scrollbarSlider.background': '#2a2a3a80',
        'scrollbarSlider.hoverBackground': '#3a3a4a80',
      },
    });
    monaco.editor.setTheme('glmpilot-dark');

    // Track cursor position
    editor.onDidChangeCursorPosition((e: any) => {
      setCursorPosition(filePath, {
        lineNumber: e.position.lineNumber,
        column: e.position.column,
      });
    });

    // Trigger completion on cursor position change
    editor.onDidChangeCursorPosition((e: any) => {
      const model = editor.getModel();
      if (!model) return;
      const position = e.position;
      const textBefore = model.getValueInRange({
        startLineNumber: 1,
        startColumn: 1,
        endLineNumber: position.lineNumber,
        endColumn: position.column,
      });
      const textAfter = model.getValueInRange({
        startLineNumber: position.lineNumber,
        startColumn: position.column,
        endLineNumber: model.getLineCount(),
        endColumn: model.getLineMaxColumn(model.getLineCount()),
      });
      requestCompletion(filePath, textBefore, textAfter, language);
    });

    editor.focus();
  };

  const handleChange: OnChange = (value) => {
    if (value !== undefined) {
      updateContent(filePath, value);
      dismissCompletion();
    }
  };

  return (
    <Editor
      height="100%"
      language={language}
      value={content}
      onChange={handleChange}
      onMount={handleMount}
      theme="glmpilot-dark"
      options={{
        fontSize,
        tabSize,
        wordWrap: wordWrap ? 'on' : 'off',
        minimap: { enabled: minimap, renderCharacters: false },
        formatOnPaste: true,
        suggestOnTriggerCharacters: true,
        quickSuggestions: { other: true, strings: true, comments: false },
        bracketPairColorization: { enabled: true },
        guides: { bracketPairs: true, indentation: true },
        scrollBeyondLastLine: false,
        smoothScrolling: true,
        cursorBlinking: 'smooth',
        cursorSmoothCaretAnimation: 'on',
        renderWhitespace: 'selection',
        lineNumbers: 'on',
        folding: true,
        links: true,
        autoClosingBrackets: 'always',
        autoClosingQuotes: 'always',
        autoIndent: 'advanced',
        padding: { top: 12 },
      }}
    />
  );
}