diff --git a/packages/cli/src/ui/components/Composer.test.tsx b/packages/cli/src/ui/components/Composer.test.tsx index 9a6155da00..cbc9b792c7 100644 --- a/packages/cli/src/ui/components/Composer.test.tsx +++ b/packages/cli/src/ui/components/Composer.test.tsx @@ -646,26 +646,6 @@ describe('Composer', () => { expect(lastFrame()).toMatch(/ShellModeIndic[\s\S]*tor/); }); - it('shows RawMarkdownIndicator when renderMarkdown is false', async () => { - const uiState = createMockUIState({ - renderMarkdown: false, - }); - - const { lastFrame } = await renderComposer(uiState); - - expect(lastFrame()).toContain('raw markdown mode'); - }); - - it('does not show RawMarkdownIndicator when renderMarkdown is true', async () => { - const uiState = createMockUIState({ - renderMarkdown: true, - }); - - const { lastFrame } = await renderComposer(uiState); - - expect(lastFrame()).not.toContain('raw markdown mode'); - }); - it.each([ [ApprovalMode.YOLO, 'YOLO'], [ApprovalMode.PLAN, 'plan'], diff --git a/packages/cli/src/ui/components/Composer.tsx b/packages/cli/src/ui/components/Composer.tsx index d30f52dddf..32ac92318c 100644 --- a/packages/cli/src/ui/components/Composer.tsx +++ b/packages/cli/src/ui/components/Composer.tsx @@ -17,7 +17,6 @@ import { ToastDisplay, shouldShowToast } from './ToastDisplay.js'; import { ApprovalModeIndicator } from './ApprovalModeIndicator.js'; import { ShellModeIndicator } from './ShellModeIndicator.js'; import { DetailedMessagesDisplay } from './DetailedMessagesDisplay.js'; -import { RawMarkdownIndicator } from './RawMarkdownIndicator.js'; import { ShortcutsHint } from './ShortcutsHint.js'; import { ShortcutsHelp } from './ShortcutsHelp.js'; import { InputPrompt } from './InputPrompt.js'; @@ -114,7 +113,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { suggestionsVisible && suggestionsPosition === 'above'; const showApprovalIndicator = !uiState.shellModeActive && !hideUiDetailsForSuggestions; - const showRawMarkdownIndicator = !uiState.renderMarkdown; let modeBleedThrough: { text: string; color: string } | null = null; switch (showApprovalModeIndicator) { case ApprovalMode.YOLO: @@ -378,26 +376,6 @@ export const Composer = ({ isFocused = true }: { isFocused?: boolean }) => { )} - {showRawMarkdownIndicator && ( - - - - )} )} diff --git a/packages/cli/src/ui/components/RawMarkdownIndicator.test.tsx b/packages/cli/src/ui/components/RawMarkdownIndicator.test.tsx deleted file mode 100644 index 0ae721ccd5..0000000000 --- a/packages/cli/src/ui/components/RawMarkdownIndicator.test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { render } from '../../test-utils/render.js'; -import { RawMarkdownIndicator } from './RawMarkdownIndicator.js'; -import { describe, it, expect, afterEach, beforeEach, vi } from 'vitest'; - -describe('RawMarkdownIndicator', () => { - const originalPlatform = process.platform; - - beforeEach(() => vi.stubEnv('FORCE_GENERIC_KEYBINDING_HINTS', '')); - - afterEach(() => { - Object.defineProperty(process, 'platform', { - value: originalPlatform, - }); - vi.unstubAllEnvs(); - }); - - it('renders correct key binding for darwin', async () => { - Object.defineProperty(process, 'platform', { - value: 'darwin', - }); - const { lastFrame, waitUntilReady, unmount } = render( - , - ); - await waitUntilReady(); - expect(lastFrame()).toContain('raw markdown mode'); - expect(lastFrame()).toContain('Option+M to toggle'); - unmount(); - }); - - it('renders correct key binding for other platforms', async () => { - Object.defineProperty(process, 'platform', { - value: 'linux', - }); - const { lastFrame, waitUntilReady, unmount } = render( - , - ); - await waitUntilReady(); - expect(lastFrame()).toContain('raw markdown mode'); - expect(lastFrame()).toContain('Alt+M to toggle'); - unmount(); - }); -}); diff --git a/packages/cli/src/ui/components/RawMarkdownIndicator.tsx b/packages/cli/src/ui/components/RawMarkdownIndicator.tsx deleted file mode 100644 index 922c30a36d..0000000000 --- a/packages/cli/src/ui/components/RawMarkdownIndicator.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type React from 'react'; -import { Box, Text } from 'ink'; -import { theme } from '../semantic-colors.js'; -import { formatCommand } from '../utils/keybindingUtils.js'; -import { Command } from '../../config/keyBindings.js'; - -export const RawMarkdownIndicator: React.FC = () => { - const modKey = formatCommand(Command.TOGGLE_MARKDOWN); - return ( - - - raw markdown mode - ({modKey} to toggle) - - - ); -}; diff --git a/packages/cli/src/ui/hooks/useAlternateBuffer.ts b/packages/cli/src/ui/hooks/useAlternateBuffer.ts index 8300df70de..3db30202b9 100644 --- a/packages/cli/src/ui/hooks/useAlternateBuffer.ts +++ b/packages/cli/src/ui/hooks/useAlternateBuffer.ts @@ -4,8 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { useState, useLayoutEffect, type RefObject } from 'react'; import { useConfig } from '../contexts/ConfigContext.js'; import type { Config } from '@google/gemini-cli-core'; +import { type DOMElement, measureElement } from 'ink'; +import { useTerminalSize } from './useTerminalSize.js'; export const isAlternateBufferEnabled = (config: Config): boolean => config.getUseAlternateBuffer(); @@ -15,3 +18,28 @@ export const useAlternateBuffer = (): boolean => { const config = useConfig(); return isAlternateBufferEnabled(config); }; + +export const useLegacyNonAlternateBufferMode = ( + rootUiRef: RefObject, +): boolean => { + const isAlternateBuffer = useAlternateBuffer(); + const { rows: terminalHeight } = useTerminalSize(); + const [isOverflowing, setIsOverflowing] = useState(false); + + useLayoutEffect(() => { + if (isAlternateBuffer || !rootUiRef.current) { + if (isOverflowing) setIsOverflowing(false); + return; + } + + const measurement = measureElement(rootUiRef.current); + // If the interactive UI is taller than the terminal height, we have a problem. + const currentlyOverflowing = measurement.height >= terminalHeight; + + if (currentlyOverflowing !== isOverflowing) { + setIsOverflowing(currentlyOverflowing); + } + }, [isAlternateBuffer, rootUiRef, terminalHeight, isOverflowing]); + + return !isAlternateBuffer && isOverflowing; +};