diff --git a/src/vs/workbench/contrib/terminalContrib/inlineHint/browser/terminal.initialHint.contribution.ts b/src/vs/workbench/contrib/terminalContrib/inlineHint/browser/terminal.initialHint.contribution.ts index b8d75933b373f..9b43d89020b4a 100644 --- a/src/vs/workbench/contrib/terminalContrib/inlineHint/browser/terminal.initialHint.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/inlineHint/browser/terminal.initialHint.contribution.ts @@ -81,8 +81,9 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm static get(instance: ITerminalInstance | IDetachedTerminalInstance): TerminalInitialHintContribution | null { return instance.getContribution(TerminalInitialHintContribution.ID); } - private _decoration: IDecoration | undefined; + private readonly _decoration = this._register(new MutableDisposable()); private _xterm: IXtermTerminal & { raw: RawXtermTerminal } | undefined; + private readonly _cursorMoveListener = this._register(new MutableDisposable()); constructor( private readonly _ctx: ITerminalContributionContext | IDetachedCompatibleTerminalContributionContext, @@ -108,6 +109,12 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm this._register(this._addon.onDidRequestCreateHint(() => this._createHint())); } + private _disposeHint(): void { + this._hintWidget?.remove(); + this._hintWidget = undefined; + this._decoration.clear(); + } + private _createHint(): void { const instance = this._ctx.instance instanceof TerminalInstance ? this._ctx.instance : undefined; const commandDetectionCapability = instance?.capabilities.get(TerminalCapability.CommandDetection); @@ -119,7 +126,7 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm return; } - if (!this._decoration) { + if (!this._decoration.value) { const marker = this._xterm.raw.registerMarker(); if (!marker) { return; @@ -129,13 +136,10 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm return; } this._register(marker); - this._decoration = this._xterm.raw.registerDecoration({ + this._decoration.value = this._xterm.raw.registerDecoration({ marker, x: this._xterm.raw.buffer.active.cursorX + 1, }); - if (this._decoration) { - this._register(this._decoration); - } } this._register(this._xterm.raw.onKey(() => this.dispose())); @@ -155,11 +159,19 @@ export class TerminalInitialHintContribution extends Disposable implements ITerm })); } - if (!this._decoration) { + // Listen to cursor move and recreate the hint (only if no input has been received) + // Fixes #286080 an issue where the hint would not reposition correctly when the terminal's prompt changed + this._cursorMoveListener.value = this._xterm.raw.onCursorMove(() => { + if (!inputModel?.value) { + this._disposeHint(); + this._createHint(); + } + }); + + if (!this._decoration.value) { return; } - this._register(this._decoration); - this._register(this._decoration.onRender((e) => { + this._register(this._decoration.value.onRender((e) => { if (!this._hintWidget && this._xterm?.isFocused) { const widget = this._register(this._instantiationService.createInstance(TerminalInitialHintWidget, instance)); this._addon?.dispose();