aboutsummaryrefslogtreecommitdiff
path: root/src/console
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2022-05-05 14:26:06 +0000
committerShin'ya Ueoka <ueokande@i-beam.org>2022-05-05 14:47:26 +0000
commit3f347b66be898b54ffa45265ae9cce7b35e04433 (patch)
treec09da52a3db9e32e36fedcdd84db670b31a16ed4 /src/console
parentcc427e967d63523b90ecc1c6aa2c864cb13b4b58 (diff)
Await loading completions done on selecting items
Diffstat (limited to 'src/console')
-rw-r--r--src/console/completion/hooks.ts38
-rw-r--r--src/console/components/CommandPrompt.tsx30
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>
);