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;
+};