Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/palette.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2026-08-29 - Truncation Awareness
**Learning:** When displaying dynamic lists in terminal UIs (such as those using `ink`), if the list is truncated to fit constraints (e.g., a `maxVisible` limit), it is important to include an explicit visual indicator to preserve user situational awareness.
**Action:** Always add an explicit UI element indicating truncation and count, rather than silently hiding items.

## 2026-08-31 - Visual Pagination and Tab-Completion Hints in Terminal UIs
**Learning:** Terminal UI lists with `maxVisible` limits that truncate suggestions (like `CommandSuggestionList`) can cause users to lose situational awareness of how many total items exist, and hidden tab-completion shortcuts can be unintuitive for users expecting standard terminal behavior. Adding pagination indicators (e.g., `1-5 of 12`) and explicit shortcut hints (`⇥ complete`) dramatically improves discoverability and clarity without cluttering the interface.
**Action:** When designing or updating truncated lists in terminal UIs (like ink), always include a visual indicator of the total item count and explicit hints for available keyboard shortcuts (like tab completion) in the status bar to preserve context and discoverability.
2 changes: 2 additions & 0 deletions src/cli/ui/components/CommandInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ export const CommandInput: React.FC<Props> = ({
suggestions={visibleSuggestions}
selectedIndex={selectedIndex - startIndex}
parentCommand={activeCommand}
totalSuggestions={suggestions.length}
startIndex={startIndex}
/>
)}
</Box>
Expand Down
11 changes: 10 additions & 1 deletion src/cli/ui/components/CommandSuggestionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ interface CommandSuggestionListProps {
selectedIndex: number;
parentCommand?: Command;
filterText?: string;
totalSuggestions: number;
startIndex: number;
}

export const CommandSuggestionList: React.FC<CommandSuggestionListProps> = ({
suggestions,
selectedIndex,
parentCommand,
totalSuggestions,
startIndex,
}) => {
if (suggestions.length === 0) return null;

Expand Down Expand Up @@ -116,7 +120,12 @@ export const CommandSuggestionList: React.FC<CommandSuggestionListProps> = ({
</Box>
<Box>
<Text color={COLORS.text.muted} dimColor>
↑↓ nav · ⏎ select · esc close
{totalSuggestions > suggestions.length && (
<Text>
{startIndex + 1}-{startIndex + suggestions.length} of {totalSuggestions} ·{' '}
</Text>
)}
↑↓ nav · ⇥ complete · ⏎ select · esc close
</Text>
</Box>
</Box>
Expand Down
54 changes: 54 additions & 0 deletions tests/unit/cli/ui/components/command-suggestion-list.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { render } from '@testing-library/react';
import React from 'react';

mock.module('ink', () => ({
Box: (props: any) => React.createElement('div', null, props.children),
Text: (props: any) => React.createElement('span', null, props.children),
}));

describe('CommandSuggestionList pagination', () => {
async function loadCommandSuggestionList() {
return (await import('../../../../../src/cli/ui/components/CommandSuggestionList.js'))
.CommandSuggestionList;
}

it('hides pagination indicator when totalSuggestions <= suggestions.length', async () => {
const CommandSuggestionList = await loadCommandSuggestionList();

const { container } = render(
<CommandSuggestionList
suggestions={[
{ name: 'test1', description: 'desc1' },
{ name: 'test2', description: 'desc2' },
]}
selectedIndex={0}
totalSuggestions={2}
startIndex={0}
/>,
);

// It should contain the shortcuts but NOT the pagination numbers
expect(container.textContent).toContain('↑↓ nav · ⇥ complete · ⏎ select · esc close');
expect(container.textContent).not.toContain('1-2 of 2');
});

it('shows pagination indicator when totalSuggestions > suggestions.length', async () => {
const CommandSuggestionList = await loadCommandSuggestionList();

const { container } = render(
<CommandSuggestionList
suggestions={[
{ name: 'test3', description: 'desc3' },
{ name: 'test4', description: 'desc4' },
]}
selectedIndex={1}
totalSuggestions={12}
startIndex={2}
/>,
);

// It should contain both the pagination numbers (3-4 of 12) and the shortcuts
expect(container.textContent).toContain('3-4 of 12');
expect(container.textContent).toContain('↑↓ nav · ⇥ complete · ⏎ select · esc close');
});
});
Loading