import { useEffect, useRef, useState } from 'react' import type { CompletionItem } from '../app/interfaces.js' import type { GatewayClient } from '../gatewayClient.js' import type { CompletionResponse } from '../gatewayTypes.js' import { asRpcResult } from '../lib/rpc.js' const TAB_PATH_RE = /((?:["']?(?:[A-Za-z]:[\\/]|\.{1,2}\/|~\/|\/|@|[^"'`\s]+\/))[^\s]*)$/ export function useCompletion(input: string, blocked: boolean, gw: GatewayClient) { const [completions, setCompletions] = useState([]) const [compIdx, setCompIdx] = useState(0) const [compReplace, setCompReplace] = useState(0) const ref = useRef('') useEffect(() => { const clear = () => { setCompletions(prev => (prev.length ? [] : prev)) setCompIdx(prev => (prev ? 0 : prev)) setCompReplace(prev => (prev ? 0 : prev)) } if (blocked) { ref.current = '' clear() return } if (input === ref.current) { return } ref.current = input const isSlash = input.startsWith('/') const pathWord = isSlash ? null : (input.match(TAB_PATH_RE)?.[1] ?? null) if (!isSlash && !pathWord) { clear() return } const pathReplace = input.length - (pathWord?.length ?? 0) const t = setTimeout(() => { if (ref.current !== input) { return } const req = isSlash ? gw.request('complete.slash', { text: input }) : gw.request('complete.path', { word: pathWord }) req .then(raw => { if (ref.current !== input) { return } const r = asRpcResult(raw) setCompletions(r?.items ?? []) setCompIdx(0) setCompReplace(isSlash ? (r?.replace_from ?? 1) : pathReplace) }) .catch((e: unknown) => { if (ref.current !== input) { return } setCompletions([ { text: '', display: 'completion unavailable', meta: e instanceof Error && e.message ? e.message : 'unavailable' } ]) setCompIdx(0) setCompReplace(isSlash ? 1 : pathReplace) }) }, 60) return () => clearTimeout(t) }, [blocked, gw, input]) return { completions, compIdx, setCompIdx, compReplace } }