mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
feat(cli): allow executing commands on perfect match (#4397)
Co-authored-by: Jenna Inouye <jinouye@google.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { InputPrompt, InputPromptProps } from './InputPrompt.js';
|
||||
import type { TextBuffer } from './shared/text-buffer.js';
|
||||
import { Config } from '@google/gemini-cli-core';
|
||||
import { CommandContext, SlashCommand } from '../commands/types.js';
|
||||
import { vi } from 'vitest';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { useShellHistory } from '../hooks/useShellHistory.js';
|
||||
import { useCompletion } from '../hooks/useCompletion.js';
|
||||
import { useInputHistory } from '../hooks/useInputHistory.js';
|
||||
@@ -341,7 +341,7 @@ describe('InputPrompt', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should complete a partial parent command and add a space', async () => {
|
||||
it('should complete a partial parent command', async () => {
|
||||
// SCENARIO: /mem -> Tab
|
||||
mockedUseCompletion.mockReturnValue({
|
||||
...mockCompletion,
|
||||
@@ -357,12 +357,12 @@ describe('InputPrompt', () => {
|
||||
stdin.write('\t'); // Press Tab
|
||||
await wait();
|
||||
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory ');
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should append a sub-command when the parent command is already complete with a space', async () => {
|
||||
// SCENARIO: /memory -> Tab (to accept 'add')
|
||||
it('should append a sub-command when the parent command is already complete', async () => {
|
||||
// SCENARIO: /memory -> Tab (to accept 'add')
|
||||
mockedUseCompletion.mockReturnValue({
|
||||
...mockCompletion,
|
||||
showSuggestions: true,
|
||||
@@ -380,13 +380,12 @@ describe('InputPrompt', () => {
|
||||
stdin.write('\t'); // Press Tab
|
||||
await wait();
|
||||
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory add ');
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory add');
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should handle the "backspace" edge case correctly', async () => {
|
||||
// SCENARIO: /memory -> Backspace -> /memory -> Tab (to accept 'show')
|
||||
// This is the critical bug we fixed.
|
||||
// SCENARIO: /memory -> Backspace -> /memory -> Tab (to accept 'show')
|
||||
mockedUseCompletion.mockReturnValue({
|
||||
...mockCompletion,
|
||||
showSuggestions: true,
|
||||
@@ -405,8 +404,8 @@ describe('InputPrompt', () => {
|
||||
stdin.write('\t'); // Press Tab
|
||||
await wait();
|
||||
|
||||
// It should NOT become '/show '. It should correctly become '/memory show '.
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory show ');
|
||||
// It should NOT become '/show'. It should correctly become '/memory show'.
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory show');
|
||||
unmount();
|
||||
});
|
||||
|
||||
@@ -426,7 +425,7 @@ describe('InputPrompt', () => {
|
||||
stdin.write('\t'); // Press Tab
|
||||
await wait();
|
||||
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/chat resume fix-foo ');
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/chat resume fix-foo');
|
||||
unmount();
|
||||
});
|
||||
|
||||
@@ -446,7 +445,7 @@ describe('InputPrompt', () => {
|
||||
await wait();
|
||||
|
||||
// The app should autocomplete the text, NOT submit.
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory ');
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/memory');
|
||||
|
||||
expect(props.onSubmit).not.toHaveBeenCalled();
|
||||
unmount();
|
||||
@@ -471,10 +470,10 @@ describe('InputPrompt', () => {
|
||||
const { stdin, unmount } = render(<InputPrompt {...props} />);
|
||||
await wait();
|
||||
|
||||
stdin.write('\t'); // Press Tab
|
||||
stdin.write('\t'); // Press Tab for autocomplete
|
||||
await wait();
|
||||
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/help ');
|
||||
expect(props.buffer.setText).toHaveBeenCalledWith('/help');
|
||||
unmount();
|
||||
});
|
||||
|
||||
@@ -505,7 +504,6 @@ describe('InputPrompt', () => {
|
||||
await wait();
|
||||
|
||||
expect(props.onSubmit).toHaveBeenCalledWith('/clear');
|
||||
expect(props.buffer.setText).not.toHaveBeenCalledWith('/clear ');
|
||||
unmount();
|
||||
});
|
||||
|
||||
@@ -530,7 +528,10 @@ describe('InputPrompt', () => {
|
||||
});
|
||||
|
||||
it('should add a newline on enter when the line ends with a backslash', async () => {
|
||||
props.buffer.setText('first line\\');
|
||||
// This test simulates multi-line input, not submission
|
||||
mockBuffer.text = 'first line\\';
|
||||
mockBuffer.cursor = [0, 11];
|
||||
mockBuffer.lines = ['first line\\'];
|
||||
|
||||
const { stdin, unmount } = render(<InputPrompt {...props} />);
|
||||
await wait();
|
||||
|
||||
@@ -162,7 +162,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
// - Otherwise, the base is everything EXCEPT the last partial part.
|
||||
const basePath =
|
||||
hasTrailingSpace || isParentPath ? parts : parts.slice(0, -1);
|
||||
const newValue = `/${[...basePath, suggestion].join(' ')} `;
|
||||
const newValue = `/${[...basePath, suggestion].join(' ')}`;
|
||||
|
||||
buffer.setText(newValue);
|
||||
} else {
|
||||
@@ -266,6 +266,12 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
// If the command is a perfect match, pressing enter should execute it.
|
||||
if (completion.isPerfectMatch && key.name === 'return') {
|
||||
handleSubmitAndClear(buffer.text);
|
||||
return;
|
||||
}
|
||||
|
||||
if (completion.showSuggestions) {
|
||||
if (completion.suggestions.length > 1) {
|
||||
if (key.name === 'up') {
|
||||
|
||||
Reference in New Issue
Block a user