mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-22 07:04:58 +00:00
fix(cli): anchor VP viewport to the top until a conversation turn exists
On a fresh VP-mode session the virtualized list holds the banner plus startup notices (tips / MOTD / info), so it is longer than one item. Keying the initial scroll anchor off list length alone selected scroll-to-end, which pinned the banner to the bottom of the full-height viewport and left the top half of the screen blank. Anchor to the top until there is an actual conversation turn (a user/user_shell history item or a pending response), then resume scroll-to-end so the latest output stays in view. Startup notices no longer count as content that forces bottom alignment. Generated with AI Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
3f6bb4f273
commit
fbe86a9e15
2 changed files with 49 additions and 3 deletions
|
|
@ -9,6 +9,7 @@ import { describe, expect, it, vi } from 'vitest';
|
|||
import { render } from 'ink-testing-library';
|
||||
import { Text } from 'ink';
|
||||
import { MainContent } from './MainContent.js';
|
||||
import { SCROLL_TO_ITEM_END } from './shared/VirtualizedList.js';
|
||||
import { UIStateContext, type UIState } from '../contexts/UIStateContext.js';
|
||||
import {
|
||||
UIActionsContext,
|
||||
|
|
@ -769,6 +770,40 @@ describe('<MainContent />', () => {
|
|||
expect(lastFrame()).toMatch(/VP_ITEM:1[\s\S]*VP_ITEM:2/);
|
||||
});
|
||||
|
||||
it('anchors to the top on a fresh session so the banner is not pushed to the bottom', () => {
|
||||
scrollableListPropsSpy.mockClear();
|
||||
|
||||
// Fresh session: banner + a startup notice, but no conversation turn.
|
||||
renderMainContent(
|
||||
createUIState({
|
||||
useTerminalBuffer: true,
|
||||
history: [{ id: 1, type: 'info', text: 'Tips: try /help' }],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(
|
||||
scrollableListPropsSpy.mock.calls.at(-1)?.[0].initialScrollIndex,
|
||||
).toBe(0);
|
||||
});
|
||||
|
||||
it('scrolls to the end once a conversation turn exists', () => {
|
||||
scrollableListPropsSpy.mockClear();
|
||||
|
||||
renderMainContent(
|
||||
createUIState({
|
||||
useTerminalBuffer: true,
|
||||
history: [
|
||||
{ id: 1, type: 'info', text: 'Tips: try /help' },
|
||||
{ id: 2, type: 'user', text: 'hello' },
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(
|
||||
scrollableListPropsSpy.mock.calls.at(-1)?.[0].initialScrollIndex,
|
||||
).toBe(SCROLL_TO_ITEM_END);
|
||||
});
|
||||
|
||||
it('keeps ShowMoreLines reachable in VP mode (regression of OverflowProvider misplacement)', () => {
|
||||
const { lastFrame } = renderMainContent(
|
||||
createUIState({
|
||||
|
|
|
|||
|
|
@ -413,6 +413,19 @@ export const MainContent = () => {
|
|||
uiState.availableTerminalHeight ?? 0,
|
||||
);
|
||||
|
||||
// Anchor the initial view to the top until there is an actual conversation
|
||||
// turn. On a fresh session the list holds only the banner plus startup
|
||||
// notices (tips / MOTD / info), which is length > 1 — so keying the anchor
|
||||
// off length alone made it scroll-to-end and pin the banner to the bottom
|
||||
// of the viewport, leaving the top half of the VP screen blank. Once the
|
||||
// user submits (or a response streams in) we resume scroll-to-end so the
|
||||
// latest output stays in view.
|
||||
const hasConversationTurn =
|
||||
pendingHistoryItems.length > 0 ||
|
||||
visibleHistory.some(
|
||||
(item) => item.type === 'user' || item.type === 'user_shell',
|
||||
);
|
||||
|
||||
return (
|
||||
<OverflowProvider>
|
||||
<ScrollableList
|
||||
|
|
@ -422,9 +435,7 @@ export const MainContent = () => {
|
|||
renderItem={renderVirtualItem}
|
||||
estimatedItemHeight={virtualEstimatedItemHeight}
|
||||
keyExtractor={virtualKeyExtractor}
|
||||
initialScrollIndex={
|
||||
allVirtualItems.length <= 1 ? 0 : SCROLL_TO_ITEM_END
|
||||
}
|
||||
initialScrollIndex={hasConversationTurn ? SCROLL_TO_ITEM_END : 0}
|
||||
isStaticItem={virtualIsStaticItem}
|
||||
containerHeight={scrollContainerHeight}
|
||||
showScrollbar={showScrollbar}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue