GLMPilot / packages /client /src /hooks /useCodeCompletion.ts
E5K7's picture
Initial commit: Rebranded to GLMPilot and migrated to GLM-5 API
c2c8c8d
import { useCallback, useRef, useEffect } from 'react';
import { useWebSocket } from './useWebSocket';
import { useEditorStore } from '@/stores/editorStore';
import { useAIStore } from '@/stores/aiStore';
import { useSettingsStore } from '@/stores/settingsStore';
export function useCodeCompletion() {
const { socket } = useWebSocket();
const { setCompletionSuggestion } = useAIStore();
const aiCompletions = useSettingsStore((s) => s.aiCompletions);
const timerRef = useRef<ReturnType<typeof setTimeout>>();
useEffect(() => {
if (!socket) return;
const handleResult = (data: { suggestion: string }) => {
if (data.suggestion) {
setCompletionSuggestion(data.suggestion);
}
};
socket.on('completion:result', handleResult);
return () => { socket.off('completion:result', handleResult); };
}, [socket, setCompletionSuggestion]);
const requestCompletion = useCallback(
(filePath: string, prefix: string, suffix: string, language: string) => {
if (!aiCompletions || !socket) return;
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
const editorState = useEditorStore.getState();
const recentFiles = editorState.recentFiles
.filter((f) => f !== filePath)
.slice(0, 3)
.map((f) => {
const file = editorState.openFiles[f];
return file ? { path: f, content: file.content } : null;
})
.filter(Boolean);
socket.emit('completion:request', {
filePath,
prefix,
suffix,
language,
contextFiles: recentFiles,
});
}, 500);
},
[socket, aiCompletions]
);
const dismissCompletion = useCallback(() => {
setCompletionSuggestion(null);
}, [setCompletionSuggestion]);
return { requestCompletion, dismissCompletion };
}