145 lines
4.1 KiB
TypeScript
145 lines
4.1 KiB
TypeScript
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
|
import { hotClass } from "@hediet/node-reload";
|
|
import { Disposable } from "@hediet/std/disposable";
|
|
import { EventEmitter } from "@hediet/std/events";
|
|
import { wait } from "@hediet/std/timer";
|
|
import { action, observable } from "mobx";
|
|
import { CancellationToken, CancellationTokenSource } from "vscode";
|
|
import { VisualizationBackend } from "../VisualizationBackend/VisualizationBackend";
|
|
import { CompletionItem, DataExtractionState } from "../webviewContract";
|
|
import { VisualizationWatch, VisualizationWatchModel, VisualizationWatchOptions } from "./VisualizationWatchModel";
|
|
|
|
@hotClass(module)
|
|
export class VisualizationWatchModelImpl implements VisualizationWatchModel {
|
|
public readonly dispose = Disposable.fn();
|
|
private readonly watchers = new Set<ObservableVisualizationWatch>();
|
|
|
|
constructor(private readonly visualizationBackend: VisualizationBackend) {
|
|
this.dispose.track(
|
|
visualizationBackend.onChange.sub(() => {
|
|
if (visualizationBackend.expressionLanguageId !== undefined) {
|
|
this.lastLanguageId = visualizationBackend.expressionLanguageId;
|
|
}
|
|
})
|
|
);
|
|
this.lastLanguageId = visualizationBackend.expressionLanguageId;
|
|
}
|
|
|
|
public createWatch(expression: string, options: VisualizationWatchOptions): VisualizationWatch {
|
|
const w = new ObservableVisualizationWatch(expression, options, this.visualizationBackend);
|
|
w.onDispose.sub(() => {
|
|
this.watchers.delete(w);
|
|
});
|
|
this.watchers.add(w);
|
|
return w;
|
|
}
|
|
|
|
@observable
|
|
private lastLanguageId: string | undefined = undefined;
|
|
|
|
get languageId(): string | undefined {
|
|
return this.lastLanguageId;
|
|
}
|
|
|
|
public getCompletions(text: string, column: number): Promise<CompletionItem[]> {
|
|
return this.visualizationBackend.getCompletions(text, column);
|
|
}
|
|
|
|
public evaluateForEffect(
|
|
expression: string
|
|
): Promise<{ result: string } | { error: string }> {
|
|
return this.visualizationBackend.evaluateForEffect(expression);
|
|
}
|
|
}
|
|
|
|
class ObservableVisualizationWatch implements VisualizationWatch {
|
|
public readonly dispose = Disposable.fn();
|
|
private readonly onDisposeEmitter = new EventEmitter();
|
|
public readonly onDispose = this.onDisposeEmitter.asEvent();
|
|
|
|
constructor(
|
|
public readonly expression: string,
|
|
options: VisualizationWatchOptions,
|
|
private readonly visualizationBackend: VisualizationBackend
|
|
) {
|
|
this._preferredDataExtractor = options.preferredDataExtractor;
|
|
|
|
this.dispose.track(
|
|
visualizationBackend.onChange.sub(() => {
|
|
this.refresh();
|
|
})
|
|
);
|
|
|
|
this.dispose.track({
|
|
dispose: () => {
|
|
this.onDisposeEmitter.emit();
|
|
},
|
|
});
|
|
|
|
this.refresh();
|
|
}
|
|
|
|
private _preferredDataExtractor: DataExtractorId | undefined = undefined;
|
|
|
|
public get preferredDataExtractor(): DataExtractorId | undefined {
|
|
return this._preferredDataExtractor;
|
|
}
|
|
|
|
@action
|
|
public setPreferredDataExtractor(id: DataExtractorId | undefined): void {
|
|
this._preferredDataExtractor = id;
|
|
this.refresh();
|
|
}
|
|
|
|
private runningRefreshOperation: Disposable | undefined;
|
|
|
|
public refresh(): void {
|
|
if (this.runningRefreshOperation) {
|
|
this.runningRefreshOperation.dispose();
|
|
}
|
|
const tokenSource = new CancellationTokenSource();
|
|
this.runningRefreshOperation = {
|
|
dispose: () => {
|
|
tokenSource.cancel();
|
|
},
|
|
};
|
|
this._refresh(tokenSource.token);
|
|
}
|
|
|
|
public sessionState: unknown = undefined;
|
|
|
|
private async _refresh(token: CancellationToken): Promise<void> {
|
|
this._state = { kind: "loading" };
|
|
const that = this;
|
|
const result = await this.visualizationBackend.getVisualizationData({
|
|
expression: this.expression,
|
|
preferredExtractorId: this.preferredDataExtractor,
|
|
sessionStore: {
|
|
get data(): unknown {
|
|
return that.sessionState;
|
|
},
|
|
set data(value: unknown) {
|
|
that.sessionState = value;
|
|
},
|
|
},
|
|
});
|
|
|
|
if (result.kind === "error") {
|
|
// give cancellation requested more time in case of errors
|
|
await wait(330);
|
|
}
|
|
|
|
if (token.isCancellationRequested) {
|
|
return;
|
|
}
|
|
|
|
this._state = result;
|
|
}
|
|
|
|
@observable
|
|
public _state: DataExtractionState = { kind: "loading" };
|
|
public get state(): DataExtractionState {
|
|
return this._state;
|
|
}
|
|
}
|