diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 50ab3ea6729..5bb629a6c09 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -2312,15 +2312,15 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF } $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise { - return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined, token); + return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined, token, resource.scheme === 'output'); } $resolveCodeLens(handle: number, symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise { - return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined, undefined); + return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined, undefined, true); } $releaseCodeLenses(handle: number, cacheId: number): void { - this._withAdapter(handle, CodeLensAdapter, adapter => Promise.resolve(adapter.releaseCodeLenses(cacheId)), undefined, undefined); + this._withAdapter(handle, CodeLensAdapter, adapter => Promise.resolve(adapter.releaseCodeLenses(cacheId)), undefined, undefined, true); } // --- declaration diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 18e4a817bfa..c6d9ae577fb 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -622,6 +622,7 @@ export class InlineChatController implements IEditorContribution { return; } if (e.kind === 'move') { + assertType(this._session); const log: typeof this._log = (msg: string, ...args: any[]) => this._log('state=_showRequest) moving inline chat', msg, ...args); log('move was requested', e.target, e.range); @@ -636,13 +637,13 @@ export class InlineChatController implements IEditorContribution { } const newEditor = editorPane.getControl(); - if (!newEditor || !isCodeEditor(newEditor) || !newEditor.hasModel()) { + if (!isCodeEditor(newEditor) || !newEditor.hasModel()) { log('new editor is either missing or not a code editor or does not have a model'); return; } - if (!this._session) { - log('controller does not have a session'); + if (this._inlineChatSessionService.getSession(newEditor, e.target)) { + log('new editor ALREADY has a session'); return; } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts index 28e5b29c7a9..01df414ec2a 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatStrategies.ts @@ -582,9 +582,9 @@ export class LiveStrategy extends EditModeStrategy { data.lensActionsViewZoneIds?.forEach(viewZoneAccessor.removeZone); data.lensActionsViewZoneIds = undefined; - lensActions?.dispose(); }); + lensActions?.dispose(); overlay?.dispose(); }; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts index 1ce7b490450..42612f493f8 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { addDisposableListener, Dimension } from 'vs/base/browser/dom'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import { toDisposable } from 'vs/base/common/lifecycle'; +import { MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { assertType } from 'vs/base/common/types'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions'; @@ -29,6 +29,7 @@ export class InlineChatZoneWidget extends ZoneWidget { readonly widget: EditorBasedInlineChatWidget; + private readonly _scrollUp = this._disposables.add(new ScrollUpState(this.editor)); private readonly _ctxCursorPosition: IContextKey<'above' | 'below' | ''>; private _dimension?: Dimension; @@ -165,6 +166,7 @@ export class InlineChatZoneWidget extends ZoneWidget { this.widget.focus(); revealZone(); + this._scrollUp.enable(); } override updatePositionAndHeight(position: Position): void { @@ -186,14 +188,15 @@ export class InlineChatZoneWidget extends ZoneWidget { return isResponseVM(candidate) && candidate.response.value.length > 0; }); - if (hasResponse && zoneTop < scrollTop) { + if (hasResponse && zoneTop < scrollTop || this._scrollUp.didScrollUp) { // don't reveal the zone if it is already out of view (unless we are still getting ready) - return () => { + // or if an outside scroll-up happened (e.g the user scrolled up to see the new content) + return this._scrollUp.runIgnored(() => { scrollState.restore(this.editor); - }; + }); } - return () => { + return this._scrollUp.runIgnored(() => { scrollState.restore(this.editor); const scrollTop = this.editor.getScrollTop(); @@ -216,7 +219,7 @@ export class InlineChatZoneWidget extends ZoneWidget { this._logService.trace('[IE] REVEAL zone', { zoneTop, lineTop, lineBottom, scrollTop, newScrollTop, forceScrollTop }); this.editor.setScrollTop(newScrollTop, ScrollType.Immediate); } - }; + }); } protected override revealRange(range: Range, isLastLine: boolean): void { @@ -229,6 +232,7 @@ export class InlineChatZoneWidget extends ZoneWidget { override hide(): void { const scrollState = StableEditorBottomScrollState.capture(this.editor); + this._scrollUp.disable(); this._ctxCursorPosition.reset(); this.widget.reset(); this.widget.chatWidget.setVisible(false); @@ -237,3 +241,54 @@ export class InlineChatZoneWidget extends ZoneWidget { scrollState.restore(this.editor); } } + +class ScrollUpState { + + private _lastScrollTop: number = this._editor.getScrollTop(); + private _didScrollUp?: boolean; + private _ignoreEvents = false; + + private readonly _listener = new MutableDisposable(); + + constructor(private readonly _editor: ICodeEditor) { } + + dispose(): void { + this._listener.dispose(); + } + + enable(): void { + this._didScrollUp = undefined; + this._listener.value = this._editor.onDidScrollChange(e => { + if (!e.scrollTopChanged || this._ignoreEvents) { + return; + } + const currentScrollTop = e.scrollTop; + if (currentScrollTop > this._lastScrollTop) { + this._listener.clear(); + this._didScrollUp = true; + } + this._lastScrollTop = currentScrollTop; + }); + } + + disable(): void { + this._listener.clear(); + this._didScrollUp = undefined; + } + + runIgnored(callback: () => void): () => void { + return () => { + this._ignoreEvents = true; + try { + return callback(); + } finally { + this._ignoreEvents = false; + } + }; + } + + get didScrollUp(): boolean | undefined { + return this._didScrollUp; + } + +} diff --git a/src/vs/workbench/contrib/output/browser/outputView.ts b/src/vs/workbench/contrib/output/browser/outputView.ts index 50d0ab01a9c..9a23e945d85 100644 --- a/src/vs/workbench/contrib/output/browser/outputView.ts +++ b/src/vs/workbench/contrib/output/browser/outputView.ts @@ -185,7 +185,6 @@ class OutputEditor extends AbstractTextResourceEditor { options.lineDecorationsWidth = 20; options.rulers = []; options.folding = false; - options.codeLens = false; options.scrollBeyondLastLine = false; options.renderLineHighlight = 'none'; options.minimap = { enabled: false };