mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 08:47:44 +00:00
Add @ command suggestions in the UI. (#219)
This commit is contained in:
@@ -8,8 +8,7 @@ import { useState, useEffect, useCallback } from 'react';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import { isNodeError } from '@gemini-code/server';
|
||||
|
||||
const MAX_SUGGESTIONS_TO_SHOW = 8;
|
||||
import { MAX_SUGGESTIONS_TO_SHOW } from '../components/SuggestionsDisplay.js';
|
||||
|
||||
export interface UseCompletionReturn {
|
||||
suggestions: string[];
|
||||
@@ -45,51 +44,64 @@ export function useCompletion(
|
||||
setIsLoadingSuggestions(false);
|
||||
}, []);
|
||||
|
||||
// --- Navigation Logic ---
|
||||
const navigateUp = useCallback(() => {
|
||||
if (suggestions.length === 0) return;
|
||||
|
||||
setActiveSuggestionIndex((prevIndex) => {
|
||||
const newIndex = prevIndex <= 0 ? suggestions.length - 1 : prevIndex - 1;
|
||||
setActiveSuggestionIndex((prevActiveIndex) => {
|
||||
// Calculate new active index, handling wrap-around
|
||||
const newActiveIndex =
|
||||
prevActiveIndex <= 0 ? suggestions.length - 1 : prevActiveIndex - 1;
|
||||
|
||||
// Adjust visible window if needed (scrolling up)
|
||||
if (newIndex < visibleStartIndex) {
|
||||
setVisibleStartIndex(newIndex);
|
||||
} else if (
|
||||
newIndex === suggestions.length - 1 &&
|
||||
suggestions.length > MAX_SUGGESTIONS_TO_SHOW
|
||||
) {
|
||||
// Handle wrapping from first to last item
|
||||
setVisibleStartIndex(
|
||||
Math.max(0, suggestions.length - MAX_SUGGESTIONS_TO_SHOW),
|
||||
);
|
||||
}
|
||||
// Adjust scroll position based on the new active index
|
||||
setVisibleStartIndex((prevVisibleStart) => {
|
||||
// Case 1: Wrapped around to the last item
|
||||
if (
|
||||
newActiveIndex === suggestions.length - 1 &&
|
||||
suggestions.length > MAX_SUGGESTIONS_TO_SHOW
|
||||
) {
|
||||
return Math.max(0, suggestions.length - MAX_SUGGESTIONS_TO_SHOW);
|
||||
}
|
||||
// Case 2: Scrolled above the current visible window
|
||||
if (newActiveIndex < prevVisibleStart) {
|
||||
return newActiveIndex;
|
||||
}
|
||||
// Otherwise, keep the current scroll position
|
||||
return prevVisibleStart;
|
||||
});
|
||||
|
||||
return newIndex;
|
||||
return newActiveIndex;
|
||||
});
|
||||
}, [suggestions.length, visibleStartIndex]);
|
||||
}, [suggestions.length]);
|
||||
|
||||
const navigateDown = useCallback(() => {
|
||||
if (suggestions.length === 0) return;
|
||||
|
||||
setActiveSuggestionIndex((prevIndex) => {
|
||||
const newIndex = prevIndex >= suggestions.length - 1 ? 0 : prevIndex + 1;
|
||||
setActiveSuggestionIndex((prevActiveIndex) => {
|
||||
// Calculate new active index, handling wrap-around
|
||||
const newActiveIndex =
|
||||
prevActiveIndex >= suggestions.length - 1 ? 0 : prevActiveIndex + 1;
|
||||
|
||||
// Adjust visible window if needed (scrolling down)
|
||||
if (newIndex >= visibleStartIndex + MAX_SUGGESTIONS_TO_SHOW) {
|
||||
setVisibleStartIndex(visibleStartIndex + 1);
|
||||
} else if (
|
||||
newIndex === 0 &&
|
||||
suggestions.length > MAX_SUGGESTIONS_TO_SHOW
|
||||
) {
|
||||
// Handle wrapping from last to first item
|
||||
setVisibleStartIndex(0);
|
||||
}
|
||||
// Adjust scroll position based on the new active index
|
||||
setVisibleStartIndex((prevVisibleStart) => {
|
||||
// Case 1: Wrapped around to the first item
|
||||
if (
|
||||
newActiveIndex === 0 &&
|
||||
suggestions.length > MAX_SUGGESTIONS_TO_SHOW
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
// Case 2: Scrolled below the current visible window
|
||||
const visibleEndIndex = prevVisibleStart + MAX_SUGGESTIONS_TO_SHOW;
|
||||
if (newActiveIndex >= visibleEndIndex) {
|
||||
return newActiveIndex - MAX_SUGGESTIONS_TO_SHOW + 1;
|
||||
}
|
||||
// Otherwise, keep the current scroll position
|
||||
return prevVisibleStart;
|
||||
});
|
||||
|
||||
return newIndex;
|
||||
return newActiveIndex;
|
||||
});
|
||||
}, [suggestions.length, visibleStartIndex]);
|
||||
// --- End Navigation Logic ---
|
||||
}, [suggestions.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isActive) {
|
||||
@@ -137,8 +149,8 @@ export function useCompletion(
|
||||
if (isMounted) {
|
||||
setSuggestions(filteredSuggestions);
|
||||
setShowSuggestions(filteredSuggestions.length > 0);
|
||||
setActiveSuggestionIndex(-1); // Reset selection on new suggestions
|
||||
setVisibleStartIndex(0); // Reset scroll on new suggestions
|
||||
setActiveSuggestionIndex(-1);
|
||||
setVisibleStartIndex(0);
|
||||
}
|
||||
} catch (error) {
|
||||
if (isNodeError(error) && error.code === 'ENOENT') {
|
||||
@@ -162,13 +174,11 @@ export function useCompletion(
|
||||
}
|
||||
};
|
||||
|
||||
// Debounce the fetch slightly
|
||||
const debounceTimeout = setTimeout(fetchSuggestions, 100);
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
clearTimeout(debounceTimeout);
|
||||
// Don't reset loading state here, let the next effect handle it or resetCompletionState
|
||||
};
|
||||
}, [query, cwd, isActive, resetCompletionState]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user