posit-dev / posit-dev/positron
Tooltip is not dismissed by a keypress that starts a keybinding chord
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 4.3k
- Forks
- 184
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 206
Description
System details:
Positron and OS details:
Positron dev build from main (fdf410ebd4), macOS 15 (Darwin 25.5.0). Reproduced against a disposable dev profile.
Session details:
n/a -- no interpreter needed.
Describe the issue:
A tooltip stays on screen through a keypress that should dismiss it, if that keypress starts a keybinding chord.
Action bar hovers are shown with persistence.hideOnKeyDown: true, so any key should hide them. HoverService._keyDown (src/vs/editor/browser/services/hoverService/hoverService.ts:517-529) asks keybindingService.softDispatch about the key first and returns early unless the result is NoMatchingKb. While a chord is pending, softDispatch returns MoreChordsNeeded, so the hide is skipped and the hover is left showing.
Chord mode self-expires after 5s of no interaction (abstractKeybindingService.ts:169), so the window is bounded, but the stale tooltip can outlive the UI it described.
Steps to reproduce the issue:
- Hover a top action bar button (e.g. New) and wait for its tooltip to appear.
- Without moving the pointer, press Cmd+K (the first key of a chord -- the status bar shows "(Ctrl+K) was pressed. Waiting for second key of chord...").
- Observe the tooltip is still visible.
For contrast, repeat with a plain key such as a in step 2: the tooltip hides immediately.
Observed via CDP, tooltip text read from .hover-contents 400ms after the keypress:
| Step | Chord key (Cmd+K) |
Plain key (a) |
|---|---|---|
| tooltip before keypress | New File/Folder |
New File/Folder |
| tooltip after keypress | New File/Folder (still up) |
null (hidden) |
Expected or desired behavior:
A keypress that starts a chord should dismiss a hover shown with hideOnKeyDown, the same as any other key. Waiting for the second key of a chord is not a reason to keep a tooltip on screen.
Were there any error messages in the UI, Output panel, or Developer Tools console?
No. The hover is simply never asked to hide.
Found while triaging a Windows-only e2e flake in Positron Notebooks: Find and Replace > Verify search widget buttons show tooltips on hover. The test-side mitigation is in #15374, which clears a wedged chord in the shared hotKeys fixture; this issue is the underlying product behavior, which that PR does not change.
E2E Triage Diagnosis
🟢 High confidence -- While a keybinding chord is pending, HoverService._keyDown skips hiding the current hover, so a tooltip survives a keypress that would normally dismiss it. Reproduced deterministically. The same chord state does NOT block later hovers, so it explains the stuck-tooltip failure mode only.
- Test: Positron Notebooks: Find and Replace > Verify search widget buttons show tooltips on hover
- Targeted failure: expect(locator(.hover-contents)).not.toBeVisible() fails with a stale tooltip still up (pattern B). Pattern A (toContainText, no widget ever created) is NOT explained by this and remains open.
- Signal: Pattern A (
toContainText, no widget created) 10 occurrences over 21 days of 669 main runs, mostly win/electron but at least one ubuntu/electron, so it is not Windows-only. Pattern B (not.toBeVisible, tooltip stuck) 1 occurrence. An earlier 14-day query reported 2 and 1 because it caps occurrences per pattern. - Hypothesis: Confirmed by local repro over CDP: with a chord pending, a showing hover survives the keypress, while a plain key hides it immediately (hoverService.ts:517-529 returns early unless softDispatch reports NoMatchingKb, and a pending chord reports MoreChordsNeeded). Chord mode self-expires after 5s (abstractKeybindingService.ts:169). hotKeys.closeAllEditors presses Cmd+K Cmd+W in an afterEach, so a dropped second keypress leaks chord mode into the next test. Falsified by the same repro: a pending chord does not stop a new hover being created, so hoverService.ts:273-282 rejects nothing here and pattern A is unexplained. Also falsified: the disabled-flip hypothesis (Chromium probe shows no mouseleave when a hovered button is disabled, mouseenter is delivered to disabled buttons, and :hover stays true).
- Supersedes: an earlier disabled-flip hypothesis for this test, and an intermediate chord-wedges-all-hovers hypothesis; both falsified by direct probes
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with HoverService._keyDown in src/vs/editor/browser/services/hoverService/hoverService.ts:517-529 and compare its softDispatch handling with the pending-chord behavior in abstractKeybindingService.ts:169. Reproduce with a visible action-bar tooltip followed by Cmd+K, then verify that a keypress starting a chord dismisses hovers configured with hideOnKeyDown, without changing plain-key behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100