fix(terminal): remove permanent link tooltip gap (#13075)

This commit is contained in:
Jinwoo Hong 2026-08-07 12:29:00 -07:00 committed by GitHub
parent 2e199cb2dd
commit 8c3e9535c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 23 deletions

View File

@ -0,0 +1,18 @@
import fs from 'node:fs'
import { describe, expect, it } from 'vitest'
const terminalCss = fs.readFileSync(new URL('./terminal.css', import.meta.url), 'utf8')
describe('terminal container geometry', () => {
it('keeps the hidden link tooltip out of the fitted terminal height', () => {
expect(terminalCss).toMatch(
/\.xterm-container\s*{[^}]*height:\s*calc\(100% - var\(--pane-padding-y, 4px\)\);/s
)
expect(terminalCss).toMatch(
/\.pane\[data-has-title\] \.xterm-container\s*{[^}]*height:\s*calc\(100% - var\(--orca-pane-title-height\)\);/s
)
expect(terminalCss).toMatch(
/\.pane-link-tooltip\s*{[^}]*height:\s*var\(--orca-terminal-link-tooltip-height\);/s
)
})
})

View File

@ -6,8 +6,7 @@
position: relative;
}
/* Why: .pane-manager-root matches no live element, so a var declared there
never resolves and every calc() using it is dropped. Keep it on :root. */
/* Shared tooltip geometry for every terminal link provider. */
:root {
--orca-terminal-link-tooltip-height: 25px;
}
@ -506,7 +505,7 @@
box-sizing: border-box;
position: relative;
width: calc(100% - var(--pane-padding-x, 4px));
height: calc(100% - var(--pane-padding-y, 4px) - var(--orca-terminal-link-tooltip-height, 25px));
height: calc(100% - var(--pane-padding-y, 4px));
margin-top: var(--pane-padding-y, 4px);
margin-left: var(--pane-padding-x, 4px);
}
@ -517,9 +516,7 @@
same amount to prevent overflow/clipping. */
.pane[data-has-title] .xterm-container {
margin-top: var(--orca-pane-title-height);
height: calc(
100% - var(--orca-pane-title-height) - var(--orca-terminal-link-tooltip-height, 25px)
); /* match margin-top and the tooltip reserve */
height: calc(100% - var(--orca-pane-title-height)); /* match margin-top */
}
/* Ghostty-style URL hover: glued to the pane's true bottom-left corner. */

View File

@ -25,8 +25,8 @@ type TooltipState = {
paneBottom: number
terminalBottom: number
tooltipTop: number
tooltipBottom: number
tooltipHeight: number
reserveHeight: number
}
async function locateUrl(page: Page, url: string): Promise<LinkProbe | null> {
@ -98,7 +98,6 @@ async function readTooltipState(page: Page, tabId: string): Promise<TooltipState
const paneRect = pane.container.getBoundingClientRect()
const terminalRect = pane.terminal.element?.parentElement?.getBoundingClientRect()
const tooltipRect = pane.linkTooltip.getBoundingClientRect()
const reserveHeight = tooltipRect.height
return {
display: pane.linkTooltip.style.display,
@ -108,8 +107,8 @@ async function readTooltipState(page: Page, tabId: string): Promise<TooltipState
paneBottom: paneRect.bottom,
terminalBottom: terminalRect?.bottom ?? 0,
tooltipTop: tooltipRect.top,
tooltipHeight: tooltipRect.height,
reserveHeight
tooltipBottom: tooltipRect.bottom,
tooltipHeight: tooltipRect.height
}
}, tabId)
}
@ -119,7 +118,7 @@ async function captureProof(page: Page, testInfo: TestInfo, name: string): Promi
}
test.describe('Issue #12656 terminal link tooltip', () => {
test('clears hover state on window blur and reserves the tooltip strip', async ({
test('clears hover state without permanently shrinking the terminal', async ({
orcaPage
}, testInfo) => {
await waitForSessionReady(orcaPage)
@ -150,6 +149,8 @@ test.describe('Issue #12656 terminal link tooltip', () => {
if (!probe) {
throw new Error('URL probe disappeared before hover')
}
const idle = await readTooltipState(orcaPage, probe.tabId)
expect(Math.abs(idle.paneBottom - idle.terminalBottom)).toBeLessThanOrEqual(1)
await expect
.poll(async () => {
await moveToLink(orcaPage, probe)
@ -160,26 +161,19 @@ test.describe('Issue #12656 terminal link tooltip', () => {
const hovered = await readTooltipState(orcaPage, probe.tabId)
expect(hovered.text).toContain(url)
expect(hovered.tooltipHeight).toBeGreaterThan(0)
expect(hovered.tooltipTop).toBeGreaterThanOrEqual(hovered.terminalBottom - 1)
// Why: bound the gap on both sides. A lower bound alone also passes when the
// reserve var fails to resolve and .xterm-container collapses to height:auto,
// which leaves a huge gap and an undersized terminal.
expect(hovered.paneBottom - hovered.terminalBottom).toBeGreaterThanOrEqual(
hovered.reserveHeight - 1
)
expect(hovered.paneBottom - hovered.terminalBottom).toBeLessThanOrEqual(
hovered.reserveHeight + 1
)
expect(Math.abs(hovered.paneBottom - hovered.terminalBottom)).toBeLessThanOrEqual(1)
expect(Math.abs(hovered.paneBottom - hovered.tooltipBottom)).toBeLessThanOrEqual(1)
expect(hovered.tooltipTop).toBeLessThan(hovered.terminalBottom)
await captureProof(orcaPage, testInfo, 'issue-12656-fixed-hover.png')
await orcaPage.evaluate(() => window.dispatchEvent(new Event('blur')))
await expect
.poll(() => readTooltipState(orcaPage, probe.tabId))
.toMatchObject({ display: 'none', currentLinkText: null, cursor: 'text' })
const cleared = await readTooltipState(orcaPage, probe.tabId)
expect(Math.abs(cleared.paneBottom - cleared.terminalBottom)).toBeLessThanOrEqual(1)
await captureProof(orcaPage, testInfo, 'issue-12656-fixed-after-blur.png')
// Keep the output assertion adjacent to the visual state checks so the
// reserved strip cannot hide the final terminal line without detection.
await expect.poll(() => getTerminalContent(orcaPage)).toContain(url)
})
})