mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 08:13:34 +00:00
fix(editor): restore snippet Tab navigation after completion
Closes #5892
This commit is contained in:
@@ -742,8 +742,7 @@ function editorIndentUnit(): string {
|
||||
}
|
||||
|
||||
function handleTab(view: EditorViewType): boolean {
|
||||
if (codeMirrorCompletionStatus?.(view.state)) return false;
|
||||
return performNormalTab(view);
|
||||
return acceptCompletionOrNextSnippetField(view) || performNormalTab(view);
|
||||
}
|
||||
|
||||
function performNormalTab(view: EditorViewType): boolean {
|
||||
@@ -1853,11 +1852,8 @@ function extendQueryEditorSelectionForView(currentView: EditorViewType): boolean
|
||||
function acceptCompletionOrNextSnippetField(view: EditorViewType): boolean {
|
||||
const completionStatus = codeMirrorCompletionStatus?.(view.state) ?? null;
|
||||
if (completionStatus === "active" && (codeMirrorAcceptCompletion?.(view) ?? false)) return true;
|
||||
// Snippet fields keep their normal immediate Tab priority when completion
|
||||
// is pending or still inside CodeMirror's interaction delay.
|
||||
if (codeMirrorNextSnippetField?.(view)) return true;
|
||||
if (completionStatus) return waitForCompletionTab(view);
|
||||
return false;
|
||||
return codeMirrorNextSnippetField?.(view) ?? false;
|
||||
}
|
||||
|
||||
function clearPendingCompletionTab() {
|
||||
@@ -1879,7 +1875,6 @@ function waitForCompletionTab(view: EditorViewType): boolean {
|
||||
|
||||
const completionStatus = codeMirrorCompletionStatus?.(view.state) ?? null;
|
||||
if (completionStatus === "active" && (codeMirrorAcceptCompletion?.(view) ?? false)) return;
|
||||
if (codeMirrorNextSnippetField?.(view)) return;
|
||||
if (completionStatus && Date.now() - startedAt < COMPLETION_TAB_MAX_WAIT_MS) {
|
||||
pendingCompletionTabTimer = setTimeout(retry, COMPLETION_TAB_RETRY_DELAY_MS);
|
||||
return;
|
||||
|
||||
@@ -141,21 +141,29 @@ describe("QueryEditor completion Tab keymap", () => {
|
||||
const harness = createHarness({ completionStatus: () => null, nextSnippetField });
|
||||
const view = createView();
|
||||
|
||||
expect(harness.acceptCompletionOrNextSnippetField(view)).toBe(true);
|
||||
expect(harness.handleTab(view)).toBe(true);
|
||||
expect(nextSnippetField).toHaveBeenCalledWith(view);
|
||||
expect(view.dispatch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("advances an available snippet field immediately while completion is pending", () => {
|
||||
it("waits for pending completion before advancing a snippet field", async () => {
|
||||
vi.useFakeTimers();
|
||||
let status: "active" | "pending" | null = "pending";
|
||||
const acceptCompletion = vi.fn(() => true);
|
||||
const nextSnippetField = vi.fn(() => true);
|
||||
const indentMore = vi.fn(() => true);
|
||||
const harness = createHarness({ completionStatus: () => "pending", nextSnippetField, indentMore });
|
||||
const harness = createHarness({ completionStatus: () => status, acceptCompletion, nextSnippetField, indentMore });
|
||||
const view = createView();
|
||||
|
||||
expect(harness.acceptCompletionOrNextSnippetField(view)).toBe(true);
|
||||
expect(nextSnippetField).toHaveBeenCalledWith(view);
|
||||
expect(vi.getTimerCount()).toBe(0);
|
||||
expect(nextSnippetField).not.toHaveBeenCalled();
|
||||
expect(vi.getTimerCount()).toBe(1);
|
||||
|
||||
status = "active";
|
||||
await vi.advanceTimersByTimeAsync(16);
|
||||
|
||||
expect(acceptCompletion).toHaveBeenCalledWith(view);
|
||||
expect(nextSnippetField).not.toHaveBeenCalled();
|
||||
expect(indentMore).not.toHaveBeenCalled();
|
||||
expect(view.dispatch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user