diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d56d54a..2a599a4 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -16,6 +16,35 @@ function isFuzzyMatch(candidate: string, query: string) { return true; } +function getCurrentPartial(input: string) { + const trimmed = input.trim(); + if (!trimmed) return ""; + if (trimmed.endsWith("/")) return ""; + const idx = trimmed.lastIndexOf("/"); + return idx >= 0 ? trimmed.slice(idx + 1) : trimmed; +} + +function renderHighlightedMatch(text: string, query: string) { + if (!query) return text; + let qIndex = 0; + const lowerQuery = query.toLowerCase(); + return text.split("").map((char, index) => { + const isMatch = + qIndex < lowerQuery.length && char.toLowerCase() === lowerQuery[qIndex]; + if (isMatch) { + qIndex += 1; + } + return ( + + {char} + + ); + }); +} + function App() { const [projectPath, setProjectPath] = React.useState(null); const [errorMsg, setErrorMsg] = React.useState(null); @@ -125,18 +154,21 @@ function App() { setMatchList(list); } - computeSuggestion().catch((error) => { - console.error(error); - if (!active) return; - setCompletionError( - error instanceof Error - ? error.message - : "Failed to compute suggestion.", - ); - }); + const debounceId = window.setTimeout(() => { + computeSuggestion().catch((error) => { + console.error(error); + if (!active) return; + setCompletionError( + error instanceof Error + ? error.message + : "Failed to compute suggestion.", + ); + }); + }, 60); return () => { active = false; + window.clearTimeout(debounceId); }; }, [pathInput, homeDir]); @@ -195,6 +227,8 @@ function App() { } } + const currentPartial = getCurrentPartial(pathInput); + return (
- {match.name}/ + {renderHighlightedMatch(match.name, currentPartial)}/ ); })}