Просмотр исходного кода

Adds better progress & logging to webview msgs

main
Eric Amodio 1 год назад
Родитель
Сommit
b0e11bd386
6 измененных файлов: 68 добавлений и 21 удалений
  1. +2
    -3
      src/plus/webviews/graph/graphWebview.ts
  2. +3
    -7
      src/plus/webviews/timeline/timelineWebview.ts
  3. +4
    -0
      src/system/decorators/log.ts
  4. +5
    -1
      src/system/logger.scope.ts
  5. +8
    -2
      src/system/logger.ts
  6. +46
    -8
      src/webviews/webviewController.ts

+ 2
- 3
src/plus/webviews/graph/graphWebview.ts Просмотреть файл

@ -580,9 +580,7 @@ export class GraphWebviewProvider implements WebviewProvider
}
if (visible) {
if (this.host.ready) {
this.host.sendPendingIpcNotifications();
}
this.host.sendPendingIpcNotifications();
const { activeSelection } = this;
if (activeSelection == null) return;
@ -1527,6 +1525,7 @@ export class GraphWebviewProvider implements WebviewProvider
return false;
}
this._notifyDidChangeStateDebounced?.cancel();
return this.host.notify(DidChangeNotificationType, { state: await this.getState() });
}

+ 3
- 7
src/plus/webviews/timeline/timelineWebview.ts Просмотреть файл

@ -460,13 +460,9 @@ export class TimelineWebviewProvider implements WebviewProvider
context = this._context;
}
const task = async () =>
this.host.notify(DidChangeNotificationType, {
state: await this.getState(context),
});
if (!this.host.isView()) return task();
return window.withProgress({ location: { viewId: this.host.id } }, task);
return this.host.notify(DidChangeNotificationType, {
state: await this.getState(context),
});
}
}

+ 4
- 0
src/system/decorators/log.ts Просмотреть файл

@ -91,6 +91,7 @@ export function log any>(options?: LogOptions, deb
const logFn = debug ? Logger.debug.bind(Logger) : Logger.log.bind(Logger);
const warnFn = Logger.warn.bind(Logger);
const errorFn = Logger.error.bind(Logger);
return (target: any, key: string, descriptor: PropertyDescriptor & Record<string, any>) => {
let fn: Function | undefined;
@ -263,6 +264,9 @@ export function log any>(options?: LogOptions, deb
} else if (exitFn === true) {
exit = `returned ${Logger.toLoggable(r)}`;
}
} else if (scope?.exitFailed) {
exit = scope.exitFailed;
exitLogFn = errorFn;
} else {
exit = 'completed';
}

+ 5
- 1
src/system/logger.scope.ts Просмотреть файл

@ -7,6 +7,7 @@ export interface LogScope {
readonly scopeId?: number;
readonly prefix: string;
exitDetails?: string;
exitFailed?: string;
}
export function clearLogScope(scopeId: number) {
@ -40,8 +41,11 @@ export function setLogScope(scopeId: number, scope: LogScope) {
scopes.set(scopeId, scope);
}
export function setLogScopeExit(scope: LogScope | undefined, details: string): void {
export function setLogScopeExit(scope: LogScope | undefined, details: string | undefined, failed?: string): void {
if (scope == null) return;
scope.exitDetails = details;
if (failed != null) {
scope.exitFailed = failed;
}
}

+ 8
- 2
src/system/logger.ts Просмотреть файл

@ -112,12 +112,18 @@ export const Logger = new (class Logger {
}
if (this.isDebugging) {
console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params, ex);
if (ex != null) {
console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params, ex);
} else {
console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params);
}
}
if (this.output == null || this.level < OrderedLevel.Error) return;
this.output.appendLine(
`${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(false, params)}\n${String(ex)}`,
`${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(false, params)}${
ex != null ? `\n${String(ex)}` : ''
}`,
);
}

+ 46
- 8
src/webviews/webviewController.ts Просмотреть файл

@ -3,10 +3,13 @@ import { Disposable, EventEmitter, Uri, ViewColumn, window, workspace } from 'vs
import { getNonce } from '@env/crypto';
import type { Commands, CustomEditorTypes, WebviewTypes, WebviewViewTypes } from '../constants';
import type { Container } from '../container';
import { pauseOnCancelOrTimeout } from '../system/cancellation';
import { executeCommand, executeCoreCommand } from '../system/command';
import { setContext } from '../system/context';
import { debug, logName } from '../system/decorators/log';
import { serialize } from '../system/decorators/serialize';
import { Logger } from '../system/logger';
import { getLogScope, setLogScopeExit } from '../system/logger.scope';
import { isPromise } from '../system/promise';
import type { WebviewContext } from '../system/webview';
import type {
@ -537,6 +540,7 @@ export class WebviewController<
params: params,
completionId: completionId,
};
const success = await this.postMessage(msg);
if (success) {
this._pendingIpcNotifications.clear();
@ -548,18 +552,52 @@ export class WebviewController<
@serialize()
@debug<WebviewController<State>['postMessage']>({
args: {
0: m => `{"id":${m.id},"method":${m.method}${m.completionId ? `,"completionId":${m.completionId}` : ''}}`,
},
args: false,
enter: m => `(${m.id}|${m.method}${m.completionId ? `+${m.completionId}` : ''})`,
})
private async postMessage(message: IpcMessage): Promise<boolean> {
if (!this._ready) return Promise.resolve(false);
// It looks like there is a bug where `postMessage` can sometimes just hang infinitely. Not sure why, but ensure we don't hang
const success = await Promise.race<boolean>([
this.webview.postMessage(message),
new Promise<boolean>(resolve => setTimeout(resolve, 5000, false)),
const scope = getLogScope();
let timeout: ReturnType<typeof setTimeout> | undefined;
// It looks like there is a bug where `postMessage` can sometimes just hang infinitely. Not sure why, but ensure we don't hang forever
const promise = Promise.race<boolean>([
this.webview.postMessage(message).then(
s => {
clearTimeout(timeout);
return s;
},
ex => {
clearTimeout(timeout);
Logger.error(scope, ex);
debugger;
return false;
},
),
new Promise<boolean>(resolve => {
timeout = setTimeout(() => {
debugger;
setLogScopeExit(scope, undefined, 'TIMEDOUT');
resolve(false);
}, 5000);
}),
]);
let success;
if (this.isView()) {
// If we are in a view, show progress if we are waiting too long
const result = await pauseOnCancelOrTimeout(promise, undefined, 100);
if (result.paused) {
success = await window.withProgress({ location: { viewId: this.id } }, () => result.value);
} else {
success = result.value;
}
} else {
success = await promise;
}
return success;
}
@ -593,7 +631,7 @@ export class WebviewController<
}
sendPendingIpcNotifications() {
if (this._pendingIpcNotifications.size === 0) return;
if (!this._ready || this._pendingIpcNotifications.size === 0) return;
const ipcs = new Map(this._pendingIpcNotifications);
this._pendingIpcNotifications.clear();

Загрузка…
Отмена
Сохранить