diff --git a/src/vs/editor/common/services/markerDecorations.ts b/src/vs/editor/common/services/markerDecorations.ts index 8b315075c93..66f1943b000 100644 --- a/src/vs/editor/common/services/markerDecorations.ts +++ b/src/vs/editor/common/services/markerDecorations.ts @@ -9,6 +9,7 @@ import { IMarker } from '../../../platform/markers/common/markers.js'; import { Event } from '../../../base/common/event.js'; import { Range } from '../core/range.js'; import { URI } from '../../../base/common/uri.js'; +import { IDisposable } from '../../../base/common/lifecycle.js'; export const IMarkerDecorationsService = createDecorator('markerDecorationsService'); @@ -20,4 +21,6 @@ export interface IMarkerDecorationsService { getMarker(uri: URI, decoration: IModelDecoration): IMarker | null; getLiveMarkers(uri: URI): [Range, IMarker][]; + + addMarkerSuppression(uri: URI, range: Range): IDisposable; } diff --git a/src/vs/editor/common/services/markerDecorationsService.ts b/src/vs/editor/common/services/markerDecorationsService.ts index 7cbd80e89f8..c25a85a6915 100644 --- a/src/vs/editor/common/services/markerDecorationsService.ts +++ b/src/vs/editor/common/services/markerDecorationsService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IMarkerService, IMarker, MarkerSeverity, MarkerTag } from '../../../platform/markers/common/markers.js'; -import { Disposable, toDisposable } from '../../../base/common/lifecycle.js'; +import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js'; import { URI } from '../../../base/common/uri.js'; import { IModelDeltaDecoration, ITextModel, IModelDecorationOptions, TrackedRangeStickiness, OverviewRulerLane, IModelDecoration, MinimapPosition, IModelDecorationMinimapOptions } from '../model.js'; import { ClassName } from '../model/intervalTree.js'; @@ -19,6 +19,7 @@ import { Emitter, Event } from '../../../base/common/event.js'; import { minimapInfo, minimapWarning, minimapError } from '../../../platform/theme/common/colorRegistry.js'; import { BidirectionalMap, ResourceMap } from '../../../base/common/map.js'; import { diffSets } from '../../../base/common/collections.js'; +import { Iterable } from '../../../base/common/iterator.js'; export class MarkerDecorationsService extends Disposable implements IMarkerDecorationsService { @@ -27,6 +28,8 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor private readonly _onDidChangeMarker = this._register(new Emitter()); readonly onDidChangeMarker: Event = this._onDidChangeMarker.event; + private readonly _suppressedRanges = new ResourceMap>(); + private readonly _markerDecorations = new ResourceMap(); constructor( @@ -56,6 +59,28 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor return markerDecorations ? markerDecorations.getMarkers() : []; } + addMarkerSuppression(uri: URI, range: Range): IDisposable { + + let suppressedRanges = this._suppressedRanges.get(uri); + if (!suppressedRanges) { + suppressedRanges = new Set(); + this._suppressedRanges.set(uri, suppressedRanges); + } + suppressedRanges.add(range); + this._handleMarkerChange([uri]); + + return toDisposable(() => { + const suppressedRanges = this._suppressedRanges.get(uri); + if (suppressedRanges) { + suppressedRanges.delete(range); + if (suppressedRanges.size === 0) { + this._suppressedRanges.delete(uri); + } + this._handleMarkerChange([uri]); + } + }); + } + private _handleMarkerChange(changedResources: readonly URI[]): void { changedResources.forEach((resource) => { const markerDecorations = this._markerDecorations.get(resource); @@ -88,7 +113,16 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor private _updateDecorations(markerDecorations: MarkerDecorations): void { // Limit to the first 500 errors/warnings - const markers = this._markerService.read({ resource: markerDecorations.model.uri, take: 500 }); + let markers = this._markerService.read({ resource: markerDecorations.model.uri, take: 500 }); + + // filter markers from suppressed ranges + const suppressedRanges = this._suppressedRanges.get(markerDecorations.model.uri); + if (suppressedRanges) { + markers = markers.filter(marker => { + return !Iterable.some(suppressedRanges, candidate => Range.areIntersectingOrTouching(candidate, marker)); + }); + } + if (markerDecorations.update(markers)) { this._onDidChangeMarker.fire(markerDecorations.model); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts index e1b70cbbc83..8aa9b86969a 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatCurrentLine.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from '../../../../base/common/lifecycle.js'; +import { Disposable, MutableDisposable } from '../../../../base/common/lifecycle.js'; import { ICodeEditor, MouseTargetType } from '../../../../editor/browser/editorBrowser.js'; import { IEditorContribution } from '../../../../editor/common/editorCommon.js'; import { localize, localize2 } from '../../../../nls.js'; @@ -29,6 +29,7 @@ import { ICommandService } from '../../../../platform/commands/common/commands.j import { InlineCompletionsController } from '../../../../editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.js'; import { ChatAgentLocation, IChatAgentService } from '../../chat/common/chatAgents.js'; import { MarkdownString } from '../../../../base/common/htmlContent.js'; +import { IMarkerDecorationsService } from '../../../../editor/common/services/markerDecorations.js'; export const CTX_INLINE_CHAT_SHOWING_HINT = new RawContextKey('inlineChatShowingHint', false, localize('inlineChatShowingHint', "Whether inline chat shows a contextual hint")); @@ -157,6 +158,7 @@ export class InlineChatHintsController extends Disposable implements IEditorCont @ICommandService commandService: ICommandService, @IKeybindingService keybindingService: IKeybindingService, @IChatAgentService chatAgentService: IChatAgentService, + @IMarkerDecorationsService markerDecorationService: IMarkerDecorationsService ) { super(); this._editor = editor; @@ -182,6 +184,7 @@ export class InlineChatHintsController extends Disposable implements IEditorCont } })); + const markerSuppression = this._store.add(new MutableDisposable()); const decos = this._editor.createDecorationsCollection(); const modelObs = observableFromEvent(editor.onDidChangeModel, () => editor.getModel()); @@ -201,6 +204,7 @@ export class InlineChatHintsController extends Disposable implements IEditorCont if (!visible || !kb || !position || ghostState !== undefined || !model) { decos.clear(); + markerSuppression.clear(); return; } @@ -234,6 +238,8 @@ export class InlineChatHintsController extends Disposable implements IEditorCont } } }]); + + markerSuppression.value = markerDecorationService.addMarkerSuppression(model.uri, model.validateRange(new Range(position.lineNumber, 1, position.lineNumber, Number.MAX_SAFE_INTEGER))); })); }