Enable progressive rendering by default for providers that support the progress method (#176323)

* Enable progressive rendering by default for providers that support the progress method

* Enable disabling progressive rendering
This commit is contained in:
Rob Lourens 2023-03-06 20:23:13 -05:00 committed by GitHub
parent 17c42736b4
commit 6248f38b38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 39 additions and 17 deletions

View file

@ -39,7 +39,7 @@ export class MainThreadInteractiveSession implements MainThreadInteractiveSessio
this._registrations.dispose();
}
async $registerInteractiveSessionProvider(handle: number, id: string): Promise<void> {
async $registerInteractiveSessionProvider(handle: number, id: string, implementsProgress: boolean): Promise<void> {
const registration = this.interactiveSessionContribService.registeredProviders.find(staticProvider => staticProvider.id === id);
if (!registration) {
throw new Error(`Provider ${id} must be declared in the package.json.`);
@ -52,6 +52,7 @@ export class MainThreadInteractiveSession implements MainThreadInteractiveSessio
const unreg = this._interactiveSessionService.registerProvider({
id,
progressiveRenderingEnabled: implementsProgress,
prepareSession: async (initialState, token) => {
const session = await this._proxy.$prepareInteractiveSession(handle, initialState, token);
if (!session) {

View file

@ -1107,7 +1107,7 @@ export interface IInteractiveResponseProgressDto {
}
export interface MainThreadInteractiveSessionShape extends IDisposable {
$registerInteractiveSessionProvider(handle: number, id: string): Promise<void>;
$registerInteractiveSessionProvider(handle: number, id: string, implementsProgress: boolean): Promise<void>;
$acceptInteractiveSessionState(sessionId: number, state: any): Promise<void>;
$addInteractiveSessionRequest(context: any): void;
$unregisterInteractiveSessionProvider(handle: number): Promise<void>;

View file

@ -43,7 +43,7 @@ export class ExtHostInteractiveSession implements ExtHostInteractiveSessionShape
registerInteractiveSessionProvider(extension: Readonly<IRelaxedExtensionDescription>, id: string, provider: vscode.InteractiveSessionProvider): vscode.Disposable {
const wrapper = new InteractiveSessionProviderWrapper(extension, provider);
this._interactiveSessionProvider.set(wrapper.handle, wrapper);
this._proxy.$registerInteractiveSessionProvider(wrapper.handle, id);
this._proxy.$registerInteractiveSessionProvider(wrapper.handle, id, !!provider.provideResponseWithProgress);
return toDisposable(() => {
this._proxy.$unregisterInteractiveSessionProvider(wrapper.handle);
this._interactiveSessionProvider.delete(wrapper.handle);

View file

@ -57,8 +57,6 @@ interface IItemHeightChangeParams {
height: number;
}
const wordRenderRate = 8; // words/sec
const forceVerboseLayoutTracing = false;
export class InteractiveListItemRenderer extends Disposable implements ITreeRenderer<InteractiveTreeItem, FuzzyScore, IInteractiveListItemTemplate> {
@ -101,8 +99,12 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
}
}
private shouldRenderProgressively(): boolean {
return this.configService.getValue('interactive.experimental.progressiveRendering');
private shouldRenderProgressively(element: IInteractiveResponseViewModel): boolean {
return !this.configService.getValue('interactive.experimental.disableProgressiveRendering') && element.progressiveResponseRenderingEnabled;
}
private getProgressiveRenderRate(): number {
return this.configService.getValue('interactive.experimental.progressiveRenderingRate') ?? 8;
}
layout(width: number): void {
@ -144,7 +146,7 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
templateData.avatar.replaceChildren(avatarIcon);
}
if (isResponseVM(element) && index === this.delegate.getListLength() - 1 && (!element.isComplete || element.renderData) && this.shouldRenderProgressively()) {
if (isResponseVM(element) && index === this.delegate.getListLength() - 1 && (!element.isComplete || element.renderData) && this.shouldRenderProgressively(element)) {
this.traceLayout('renderElement', `start progressive render ${kind}, index=${index}`);
const progressiveRenderingDisposables = templateData.elementDisposables.add(new DisposableStore());
const timer = templateData.elementDisposables.add(new IntervalTimer());
@ -154,7 +156,7 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
}
};
runProgressiveRender();
timer.cancelAndSet(runProgressiveRender, 1000 / wordRenderRate);
timer.cancelAndSet(runProgressiveRender, 1000 / this.getProgressiveRenderRate());
} else if (isResponseVM(element)) {
this.basicRenderElement(element.response.value, element, index, templateData);
} else {
@ -240,7 +242,7 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend
const renderData = element.renderData ?? { renderPosition: 0, renderTime: 0 };
const numWordsToRender = renderData.renderTime === 0 ?
1 :
renderData.renderPosition + Math.floor((Date.now() - renderData.renderTime) / 1000 * wordRenderRate);
renderData.renderPosition + Math.floor((Date.now() - renderData.renderTime) / 1000 * this.getProgressiveRenderRate());
if (numWordsToRender === renderData.renderPosition) {
return undefined;

View file

@ -310,7 +310,7 @@ export class InteractiveSessionWidget extends Disposable {
throw new Error('Failed to start session');
}
this.viewModel = this.viewModelDisposables.add(new InteractiveSessionViewModel(model));
this.viewModel = this.viewModelDisposables.add(this.instantiationService.createInstance(InteractiveSessionViewModel, model));
this.viewModelDisposables.add(this.viewModel.onDidChange(() => this.onDidChangeItems()));
this.viewModelDisposables.add(this.viewModel.onDidDisposeModel(() => {
this.viewModel = undefined;

View file

@ -101,6 +101,7 @@ export interface IInteractiveSessionModel {
readonly onDidDispose: Event<void>;
readonly onDidChange: Event<IInteractiveSessionChangeEvent>;
readonly sessionId: number;
readonly providerId: string;
getRequests(): IInteractiveRequestModel[];
}

View file

@ -35,8 +35,9 @@ export interface IInteractiveProgress {
export interface IPersistedInteractiveState { }
export interface IInteractiveProvider {
id: string;
iconUrl?: string;
readonly id: string;
readonly progressiveRenderingEnabled?: boolean;
readonly iconUrl?: string;
prepareSession(initialState: IPersistedInteractiveState | undefined, token: CancellationToken): ProviderResult<IInteractiveSession | undefined>;
resolveRequest?(session: IInteractiveSession, context: any, token: CancellationToken): ProviderResult<IInteractiveRequest>;
provideSuggestions?(token: CancellationToken): ProviderResult<string[] | undefined>;
@ -48,6 +49,7 @@ export const IInteractiveSessionService = createDecorator<IInteractiveSessionSer
export interface IInteractiveSessionService {
_serviceBrand: undefined;
registerProvider(provider: IInteractiveProvider): IDisposable;
progressiveRenderingEnabled(providerId: string): boolean;
startSession(providerId: string, allowRestoringSession: boolean, token: CancellationToken): Promise<InteractiveSessionModel | undefined>;
/**

View file

@ -49,6 +49,10 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
}));
}
progressiveRenderingEnabled(providerId: string): boolean {
return this._providers.get(providerId)?.progressiveRenderingEnabled ?? false;
}
private trace(method: string, message: string): void {
this.logService.trace(`[InteractiveSessionService#${method}] ${message}`);
}

View file

@ -8,6 +8,7 @@ import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IInteractiveRequestModel, IInteractiveResponseModel, IInteractiveSessionModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel';
import { IInteractiveSessionService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
export function isRequestVM(item: unknown): item is IInteractiveRequestViewModel {
return !isResponseVM(item);
@ -46,6 +47,7 @@ export interface IInteractiveResponseViewModel {
readonly response: IMarkdownString;
readonly isComplete: boolean;
readonly followups?: string[];
readonly progressiveResponseRenderingEnabled: boolean;
renderData?: IInteractiveResponseRenderData;
currentRenderedHeight: number | undefined;
}
@ -63,13 +65,23 @@ export class InteractiveSessionViewModel extends Disposable {
return this._model.sessionId;
}
constructor(private readonly _model: IInteractiveSessionModel) {
private readonly _progressiveResponseRenderingEnabled: boolean;
get progressiveResponseRenderingEnabled(): boolean {
return this._progressiveResponseRenderingEnabled;
}
constructor(
private readonly _model: IInteractiveSessionModel,
@IInteractiveSessionService private readonly interactiveSessionService: IInteractiveSessionService
) {
super();
this._progressiveResponseRenderingEnabled = this.interactiveSessionService.progressiveRenderingEnabled(this._model.providerId);
_model.getRequests().forEach((request, i) => {
this._items.push(new InteractiveRequestViewModel(request));
if (request.response) {
this._items.push(new InteractiveResponseViewModel(request.response));
this._items.push(new InteractiveResponseViewModel(request.response, this.progressiveResponseRenderingEnabled));
}
});
@ -92,7 +104,7 @@ export class InteractiveSessionViewModel extends Disposable {
}
private onAddResponse(responseModel: IInteractiveResponseModel) {
const response = new InteractiveResponseViewModel(responseModel);
const response = new InteractiveResponseViewModel(responseModel, this.progressiveResponseRenderingEnabled);
this._register(response.onDidChange(() => this._onDidChange.fire()));
this._items.push(response);
}
@ -171,7 +183,7 @@ export class InteractiveResponseViewModel extends Disposable implements IInterac
currentRenderedHeight: number | undefined;
constructor(private readonly _model: IInteractiveResponseModel) {
constructor(private readonly _model: IInteractiveResponseModel, public readonly progressiveResponseRenderingEnabled: boolean) {
super();
this._isPlaceholder = !_model.response.value && !_model.isComplete;