diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2022-05-05 14:26:06 +0000 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2022-05-05 14:47:26 +0000 |
commit | 3f347b66be898b54ffa45265ae9cce7b35e04433 (patch) | |
tree | c09da52a3db9e32e36fedcdd84db670b31a16ed4 /src | |
parent | cc427e967d63523b90ecc1c6aa2c864cb13b4b58 (diff) |
Await loading completions done on selecting items
Diffstat (limited to 'src')
-rw-r--r-- | src/console/completion/hooks.ts | 38 | ||||
-rw-r--r-- | src/console/components/CommandPrompt.tsx | 30 |
2 files changed, 54 insertions, 14 deletions
diff --git a/src/console/completion/hooks.ts b/src/console/completion/hooks.ts index a2e8bde..cc6cd30 100644 --- a/src/console/completion/hooks.ts +++ b/src/console/completion/hooks.ts @@ -175,6 +175,7 @@ export const useCompletions = (source: string) => { const dispatch = React.useContext(CompletionDispatchContext); const commandLineParser = React.useMemo(() => new CommandLineParser(), []); const [completionTypes] = useGetCompletionTypes(); + const [loading, setLoading] = React.useState(false); const queryCompletions = React.useCallback( (text: string, completionTypes: CompletionType[]) => { @@ -192,40 +193,57 @@ export const useCompletions = (source: string) => { return; } } + + setLoading(true); switch (cmd?.command) { case Command.Open: case Command.TabOpen: case Command.WindowOpen: getOpenCompletions(cmd.command, cmd.args, completionTypes).then( - (completions) => dispatch(actions.setCompletions(completions)) + (completions) => { + dispatch(actions.setCompletions(completions)); + setLoading(false); + } ); break; case Command.Buffer: getTabCompletions(cmd.command, cmd.args, false).then( - (completions) => dispatch(actions.setCompletions(completions)) + (completions) => { + dispatch(actions.setCompletions(completions)); + setLoading(false); + } ); break; case Command.BufferDelete: case Command.BuffersDelete: - getTabCompletions(cmd.command, cmd.args, true).then((completions) => - dispatch(actions.setCompletions(completions)) + getTabCompletions(cmd.command, cmd.args, true).then( + (completions) => { + dispatch(actions.setCompletions(completions)); + setLoading(false); + } ); break; case Command.BufferDeleteForce: case Command.BuffersDeleteForce: getTabCompletions(cmd.command, cmd.args, false).then( - (completions) => dispatch(actions.setCompletions(completions)) + (completions) => { + dispatch(actions.setCompletions(completions)); + setLoading(false); + } ); break; case Command.Set: - getPropertyCompletions(cmd.command, cmd.args).then((completions) => - dispatch(actions.setCompletions(completions)) + getPropertyCompletions(cmd.command, cmd.args).then( + (completions) => { + dispatch(actions.setCompletions(completions)); + setLoading(false); + } ); break; } } }, - [dispatch] + [dispatch, source] ); React.useEffect(() => { @@ -237,7 +255,7 @@ export const useCompletions = (source: string) => { queryCompletions(source, completionTypes); }, [source, completionTypes]); - return { completions: state.completions }; + return { completions: state.completions, loading }; }; export const useSelectCompletion = () => { @@ -257,7 +275,7 @@ export const useSelectCompletion = () => { } const items = state.completions.map((g) => g.items).flat(); return items[state.select]?.value || ""; - }, [state.completionSource, state.select]); + }, [state.completionSource, state.select, state.completions]); return { select: state.select, diff --git a/src/console/components/CommandPrompt.tsx b/src/console/components/CommandPrompt.tsx index 89acf57..5d4cb6e 100644 --- a/src/console/components/CommandPrompt.tsx +++ b/src/console/components/CommandPrompt.tsx @@ -18,15 +18,23 @@ interface Props { initialInputValue: string; } +enum SelectQueueType { + SelectNext, + SelectPrev, +} + const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { const hide = useHide(); const [inputValue, setInputValue] = React.useState(initialInputValue); const debouncedValue = useDebounce(inputValue, 100); - const { completions } = useCompletions(debouncedValue); + const { completions, loading } = useCompletions(debouncedValue); const { select, currentValue, selectNext, selectPrev } = useSelectCompletion(); const execCommand = useExecCommand(); + // The value is set after the user presses Tab (or Shift+Tab) key and waiting the completion + const [selecting, setSelecting] = React.useState<SelectQueueType>(); + useAutoResize(); const onBlur = () => { @@ -67,9 +75,9 @@ const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { execCommand(value); hide(); } else if (isNextKey(e)) { - selectNext(); + setSelecting(SelectQueueType.SelectNext); } else if (isPrevKey(e)) { - selectPrev(); + setSelecting(SelectQueueType.SelectPrev); } else { return; } @@ -78,6 +86,20 @@ const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { e.preventDefault(); }; + React.useEffect(() => { + if (inputValue !== debouncedValue || loading) { + // The completions of the latest input value are not fetched + return; + } + if (selecting === SelectQueueType.SelectNext) { + selectNext(); + setSelecting(undefined); + } else if (selecting === SelectQueueType.SelectPrev) { + selectPrev(); + setSelecting(undefined); + } + }, [inputValue, debouncedValue, selecting, loading]); + const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { const text = e.target.value; setInputValue(text); @@ -95,7 +117,7 @@ const CommandPromptInner: React.FC<Props> = ({ initialInputValue }) => { onBlur={onBlur} onKeyDown={onKeyDown} onChange={onChange} - value={select == -1 ? inputValue : currentValue} + value={select == -1 || loading ? inputValue : currentValue} /> </ConsoleWrapper> ); |