Debounce autocomplete

This commit is contained in:
Gregory Schier
2023-03-08 11:25:20 -08:00
parent 657c6ad9a9
commit f976397283
12 changed files with 117 additions and 33 deletions

View File

@@ -67,7 +67,7 @@ export default function Editor({
// Create codemirror instance when ref initializes
useEffect(() => {
if (ref.current === null) return;
console.log('INIT EDITOR');
// console.log('INIT EDITOR');
let view: EditorView | null = null;
try {
const langHolder = new Compartment();
@@ -102,7 +102,7 @@ export default function Editor({
// Update language extension when contentType changes
useEffect(() => {
if (cm === null) return;
console.log('UPDATE LANG');
// console.log('UPDATE LANG');
const ext = getLanguageExtension({ contentType, useTemplating });
cm.view.dispatch({ effects: cm.langHolder.reconfigure(ext) });
}, [contentType]);
@@ -110,6 +110,7 @@ export default function Editor({
return (
<div
ref={ref}
dangerouslySetInnerHTML={{ __html: '' }}
className={classnames(
className,
'cm-wrapper text-base bg-background',

View File

@@ -0,0 +1,29 @@
import { closeCompletion, startCompletion } from '@codemirror/autocomplete';
import { EditorView } from 'codemirror';
import { debounce } from 'lodash';
/*
* Debounce autocomplete until user stops typing for `millis` milliseconds.
*/
export function debouncedAutocompletionDisplay({ millis }: { millis: number }) {
// TODO: Figure out how to show completion without setting context.explicit = true
const debouncedStartCompletion = debounce(function (view: EditorView) {
startCompletion(view);
}, millis);
return EditorView.updateListener.of(({ view, docChanged }) => {
// const completions = currentCompletions(view.state);
// const status = completionStatus(view.state);
// If the document hasn't changed, we don't need to do anything
if (!docChanged) return;
if (view.state.doc.length === 0) {
debouncedStartCompletion.cancel();
closeCompletion(view);
return;
}
debouncedStartCompletion(view);
});
}

View File

@@ -33,6 +33,7 @@ import {
rectangularSelection,
} from '@codemirror/view';
import { tags as t } from '@lezer/highlight';
import { debouncedAutocompletionDisplay } from './autocomplete';
import { twig } from './twig/extension';
import { url } from './url/extension';
@@ -107,7 +108,8 @@ export const baseExtensions = [
drawSelection(),
dropCursor(),
bracketMatching(),
autocompletion({ closeOnBlur: true, interactionDelay: 200 }),
debouncedAutocompletionDisplay({ millis: 1000 }),
autocompletion({ closeOnBlur: true, interactionDelay: 200, activateOnTyping: false }),
syntaxHighlighting(myHighlightStyle),
EditorState.allowMultipleSelections.of(true),
];

View File

@@ -47,6 +47,7 @@ export function completions(context: CompletionContext) {
label: toStartOfVariable ? `${openTag}${v.name}${closeTag}` : v.name,
apply: `${openTag}${v.name}${closeTag}`,
type: 'variable',
matchLen,
}))
// Filter out exact matches
.filter((o) => o.label !== toMatch.text),

View File

@@ -37,7 +37,7 @@ export function HeaderEditor() {
};
return (
<form onSubmit={handleSubmit}>
<form onSubmit={handleSubmit} className="min-h-[30vh]">
<VStack space={2}>
{headers.map((header, i) => (
<FormRow

View File

@@ -131,7 +131,7 @@ export function ResponsePane({ requestId, className }: Props) {
) : response?.body ? (
<Editor
className="bg-gray-50 dark:!bg-gray-100"
valueKey={`${contentType}:${response.body}`}
valueKey={`${contentType}:${response.updatedAt}`}
defaultValue={response?.body}
contentType={contentType}
/>

View File

@@ -22,7 +22,6 @@ export function Sidebar({ className, activeRequestId, workspaceId, requests, ...
const createRequest = useRequestCreate({ workspaceId, navigateAfter: true });
const { appearance, toggleAppearance } = useTheme();
const [open, setOpen] = useState<boolean>(false);
console.log('OPEN', open);
return (
<div
className={classnames(className, 'w-52 bg-gray-100 h-full border-r border-gray-200')}