diff options
-rw-r--r-- | src/console/completion/hooks.ts | 135 | ||||
-rw-r--r-- | src/console/components/CommandPrompt.tsx | 6 | ||||
-rw-r--r-- | src/console/hooks/useDebounce.ts | 19 |
3 files changed, 71 insertions, 89 deletions
diff --git a/src/console/completion/hooks.ts b/src/console/completion/hooks.ts index 62baab4..3a2ec33 100644 --- a/src/console/completion/hooks.ts +++ b/src/console/completion/hooks.ts @@ -36,41 +36,6 @@ const propertyDocs: { [key: string]: string } = { const completionClient = new CompletionClient(); -const useDelayedCallback = <T extends unknown, U extends unknown>( - callback: (arg1: T, arg2: U) => void, - timeout: number -) => { - const [timer, setTimer] = React.useState< - ReturnType<typeof setTimeout> | undefined - >(); - const [enabled, setEnabled] = React.useState(false); - - const enableDelay = React.useCallback(() => { - setEnabled(true); - }, [setEnabled]); - - const delayedCallback = React.useCallback( - (arg1: T, arg2: U) => { - if (enabled) { - if (typeof timer !== "undefined") { - clearTimeout(timer); - } - const id = setTimeout(() => { - callback(arg1, arg2); - clearTimeout(timer!); - setTimer(undefined); - }, timeout); - setTimer(id); - } else { - callback(arg1, arg2); - } - }, - [enabled, timer] - ); - - return { enableDelay, delayedCallback }; -}; - const getCommandCompletions = async (query: string): Promise<Completions> => { const items = Object.entries(commandDocs) .filter(([name]) => name.startsWith(query)) @@ -215,60 +180,56 @@ export const useCompletions = () => { dispatch(actions.setCompletionSource(source)); }, []); - const { delayedCallback: queryCompletions, enableDelay } = useDelayedCallback( - React.useCallback( - (text: string, completionTypes: CompletionType[]) => { - const phase = commandLineParser.inputPhase(text); - if (phase === InputPhase.OnCommand) { - getCommandCompletions(text).then((completions) => - dispatch(actions.setCompletions(completions)) - ); - } else { - let cmd: CommandLine | null = null; - try { - cmd = commandLineParser.parse(text); - } catch (e) { - if (e instanceof UnknownCommandError) { - return; - } - } - switch (cmd?.command) { - case Command.Open: - case Command.TabOpen: - case Command.WindowOpen: - getOpenCompletions(cmd.command, cmd.args, completionTypes).then( - (completions) => dispatch(actions.setCompletions(completions)) - ); - break; - case Command.Buffer: - getTabCompletions(cmd.command, cmd.args, false).then( - (completions) => dispatch(actions.setCompletions(completions)) - ); - break; - case Command.BufferDelete: - case Command.BuffersDelete: - getTabCompletions(cmd.command, cmd.args, true).then( - (completions) => dispatch(actions.setCompletions(completions)) - ); - break; - case Command.BufferDeleteForce: - case Command.BuffersDeleteForce: - getTabCompletions(cmd.command, cmd.args, false).then( - (completions) => dispatch(actions.setCompletions(completions)) - ); - break; - case Command.Set: - getPropertyCompletions(cmd.command, cmd.args).then( - (completions) => dispatch(actions.setCompletions(completions)) - ); - break; + const queryCompletions = React.useCallback( + (text: string, completionTypes: CompletionType[]) => { + const phase = commandLineParser.inputPhase(text); + if (phase === InputPhase.OnCommand) { + getCommandCompletions(text).then((completions) => + dispatch(actions.setCompletions(completions)) + ); + } else { + let cmd: CommandLine | null = null; + try { + cmd = commandLineParser.parse(text); + } catch (e) { + if (e instanceof UnknownCommandError) { + return; } - enableDelay(); } - }, - [dispatch] - ), - 100 + switch (cmd?.command) { + case Command.Open: + case Command.TabOpen: + case Command.WindowOpen: + getOpenCompletions(cmd.command, cmd.args, completionTypes).then( + (completions) => dispatch(actions.setCompletions(completions)) + ); + break; + case Command.Buffer: + getTabCompletions(cmd.command, cmd.args, false).then( + (completions) => dispatch(actions.setCompletions(completions)) + ); + break; + case Command.BufferDelete: + case Command.BuffersDelete: + getTabCompletions(cmd.command, cmd.args, true).then((completions) => + dispatch(actions.setCompletions(completions)) + ); + break; + case Command.BufferDeleteForce: + case Command.BuffersDeleteForce: + getTabCompletions(cmd.command, cmd.args, false).then( + (completions) => dispatch(actions.setCompletions(completions)) + ); + break; + case Command.Set: + getPropertyCompletions(cmd.command, cmd.args).then((completions) => + dispatch(actions.setCompletions(completions)) + ); + break; + } + } + }, + [dispatch] ); React.useEffect(() => { diff --git a/src/console/components/CommandPrompt.tsx b/src/console/components/CommandPrompt.tsx index 0e2506c..0312fe4 100644 --- a/src/console/components/CommandPrompt.tsx +++ b/src/console/components/CommandPrompt.tsx @@ -3,6 +3,7 @@ import Completion from "./console/Completion"; import Input from "./console//Input"; import styled from "styled-components"; import { useCompletions, useSelectCompletion } from "../completion/hooks"; +import useDebounce from "../hooks/useDebounce"; import useAutoResize from "../hooks/useAutoResize"; import { CompletionProvider } from "../completion/provider"; import { useExecCommand, useHide } from "../app/hooks"; @@ -20,6 +21,7 @@ interface Props { const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { const hide = useHide(); const [inputValue, setInputValue] = React.useState(initialInputValue); + const debouncedValue = useDebounce(inputValue, 100); const { completions, updateCompletions } = useCompletions(); const { select, currentValue, selectNext, selectPrev } = useSelectCompletion(); @@ -82,8 +84,8 @@ const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { }; React.useEffect(() => { - updateCompletions(inputValue); - }, [inputValue]); + updateCompletions(debouncedValue); + }, [debouncedValue]); return ( <ConsoleWrapper> diff --git a/src/console/hooks/useDebounce.ts b/src/console/hooks/useDebounce.ts new file mode 100644 index 0000000..838ff34 --- /dev/null +++ b/src/console/hooks/useDebounce.ts @@ -0,0 +1,19 @@ +import React from "react"; + +const useDebounce = <T extends unknown>(value: T, delay: number) => { + const [debouncedValue, setDebouncedValue] = React.useState(value); + + React.useEffect(() => { + const timer = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(timer); + }; + }, [value, delay]); + + return debouncedValue; +}; + +export default useDebounce; |