mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-23 03:39:23 +00:00
Add webview restoration api proposal (#46380)
Adds a proposed webiew serialization api that allows webviews to be restored automatically when vscode restarts
This commit is contained in:
@@ -18,37 +18,85 @@ const localize = nls.loadMessageBundle();
|
||||
|
||||
export class MarkdownPreview {
|
||||
|
||||
public static previewViewType = 'markdown.preview';
|
||||
public static viewType = 'markdown.preview';
|
||||
|
||||
private readonly webview: vscode.Webview;
|
||||
private throttleTimer: any;
|
||||
private initialLine: number | undefined = undefined;
|
||||
private line: number | undefined = undefined;
|
||||
private readonly disposables: vscode.Disposable[] = [];
|
||||
private firstUpdate = true;
|
||||
private currentVersion?: { resource: vscode.Uri, version: number };
|
||||
private forceUpdate = false;
|
||||
private isScrolling = false;
|
||||
|
||||
constructor(
|
||||
private _resource: vscode.Uri,
|
||||
public static revive(
|
||||
webview: vscode.Webview,
|
||||
state: any,
|
||||
contentProvider: MarkdownContentProvider,
|
||||
previewConfigurations: MarkdownPreviewConfigurationManager,
|
||||
logger: Logger,
|
||||
topmostLineMonitor: MarkdownFileTopmostLineMonitor
|
||||
): MarkdownPreview {
|
||||
const resource = vscode.Uri.parse(state.resource);
|
||||
const locked = state.locked;
|
||||
const line = state.line;
|
||||
|
||||
const preview = new MarkdownPreview(
|
||||
webview,
|
||||
resource,
|
||||
locked,
|
||||
contentProvider,
|
||||
previewConfigurations,
|
||||
logger,
|
||||
topmostLineMonitor);
|
||||
|
||||
if (!isNaN(line)) {
|
||||
preview.line = line;
|
||||
}
|
||||
return preview;
|
||||
}
|
||||
|
||||
public static create(
|
||||
resource: vscode.Uri,
|
||||
previewColumn: vscode.ViewColumn,
|
||||
public locked: boolean,
|
||||
private readonly contentProvider: MarkdownContentProvider,
|
||||
private readonly previewConfigurations: MarkdownPreviewConfigurationManager,
|
||||
private readonly logger: Logger,
|
||||
locked: boolean,
|
||||
contentProvider: MarkdownContentProvider,
|
||||
previewConfigurations: MarkdownPreviewConfigurationManager,
|
||||
logger: Logger,
|
||||
topmostLineMonitor: MarkdownFileTopmostLineMonitor,
|
||||
private readonly contributions: MarkdownContributions
|
||||
) {
|
||||
this.webview = vscode.window.createWebview(
|
||||
MarkdownPreview.previewViewType,
|
||||
this.getPreviewTitle(this._resource),
|
||||
contributions: MarkdownContributions
|
||||
): MarkdownPreview {
|
||||
const webview = vscode.window.createWebview(
|
||||
MarkdownPreview.viewType,
|
||||
MarkdownPreview.getPreviewTitle(resource, locked),
|
||||
previewColumn, {
|
||||
enableScripts: true,
|
||||
enableCommandUris: true,
|
||||
enableFindWidget: true,
|
||||
localResourceRoots: this.getLocalResourceRoots(_resource)
|
||||
localResourceRoots: MarkdownPreview.getLocalResourceRoots(resource, contributions)
|
||||
});
|
||||
|
||||
return new MarkdownPreview(
|
||||
webview,
|
||||
resource,
|
||||
locked,
|
||||
contentProvider,
|
||||
previewConfigurations,
|
||||
logger,
|
||||
topmostLineMonitor);
|
||||
}
|
||||
|
||||
private constructor(
|
||||
webview: vscode.Webview,
|
||||
private _resource: vscode.Uri,
|
||||
public locked: boolean,
|
||||
private readonly contentProvider: MarkdownContentProvider,
|
||||
private readonly previewConfigurations: MarkdownPreviewConfigurationManager,
|
||||
private readonly logger: Logger,
|
||||
topmostLineMonitor: MarkdownFileTopmostLineMonitor
|
||||
) {
|
||||
this.webview = webview;
|
||||
|
||||
this.webview.onDidDispose(() => {
|
||||
this.dispose();
|
||||
}, null, this.disposables);
|
||||
@@ -111,6 +159,14 @@ export class MarkdownPreview {
|
||||
return this._resource;
|
||||
}
|
||||
|
||||
public get state() {
|
||||
return {
|
||||
resource: this.resource.toString(),
|
||||
locked: this.locked,
|
||||
line: this.line
|
||||
};
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this._onDisposeEmitter.fire();
|
||||
|
||||
@@ -124,9 +180,7 @@ export class MarkdownPreview {
|
||||
public update(resource: vscode.Uri) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor && editor.document.uri.fsPath === resource.fsPath) {
|
||||
this.initialLine = getVisibleLine(editor);
|
||||
} else {
|
||||
this.initialLine = undefined;
|
||||
this.line = getVisibleLine(editor);
|
||||
}
|
||||
|
||||
// If we have changed resources, cancel any pending updates
|
||||
@@ -169,6 +223,10 @@ export class MarkdownPreview {
|
||||
return this._resource.fsPath === resource.fsPath;
|
||||
}
|
||||
|
||||
public isWebviewOf(webview: vscode.Webview): boolean {
|
||||
return this.webview === webview;
|
||||
}
|
||||
|
||||
public matchesResource(
|
||||
otherResource: vscode.Uri,
|
||||
otherViewColumn: vscode.ViewColumn | undefined,
|
||||
@@ -195,11 +253,11 @@ export class MarkdownPreview {
|
||||
|
||||
public toggleLock() {
|
||||
this.locked = !this.locked;
|
||||
this.webview.title = this.getPreviewTitle(this._resource);
|
||||
this.webview.title = MarkdownPreview.getPreviewTitle(this._resource, this.locked);
|
||||
}
|
||||
|
||||
private getPreviewTitle(resource: vscode.Uri): string {
|
||||
return this.locked
|
||||
private static getPreviewTitle(resource: vscode.Uri, locked: boolean): string {
|
||||
return locked
|
||||
? localize('lockedPreviewTitle', '[Preview] {0}', path.basename(resource.fsPath))
|
||||
: localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath));
|
||||
}
|
||||
@@ -216,7 +274,7 @@ export class MarkdownPreview {
|
||||
|
||||
if (typeof topLine === 'number') {
|
||||
this.logger.log('updateForView', { markdownFile: resource });
|
||||
this.initialLine = topLine;
|
||||
this.line = topLine;
|
||||
this.webview.postMessage({
|
||||
type: 'updateView',
|
||||
line: topLine,
|
||||
@@ -233,25 +291,28 @@ export class MarkdownPreview {
|
||||
|
||||
const document = await vscode.workspace.openTextDocument(resource);
|
||||
if (!this.forceUpdate && this.currentVersion && this.currentVersion.resource.fsPath === resource.fsPath && this.currentVersion.version === document.version) {
|
||||
if (this.initialLine) {
|
||||
this.updateForView(resource, this.initialLine);
|
||||
if (this.line) {
|
||||
this.updateForView(resource, this.line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.forceUpdate = false;
|
||||
|
||||
this.currentVersion = { resource, version: document.version };
|
||||
this.contentProvider.provideTextDocumentContent(document, this.previewConfigurations, this.initialLine)
|
||||
this.contentProvider.provideTextDocumentContent(document, this.previewConfigurations, this.line)
|
||||
.then(content => {
|
||||
if (this._resource === resource) {
|
||||
this.webview.title = this.getPreviewTitle(this._resource);
|
||||
this.webview.title = MarkdownPreview.getPreviewTitle(this._resource, this.locked);
|
||||
this.webview.html = content;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getLocalResourceRoots(resource: vscode.Uri): vscode.Uri[] {
|
||||
const baseRoots = this.contributions.previewResourceRoots;
|
||||
private static getLocalResourceRoots(
|
||||
resource: vscode.Uri,
|
||||
contributions: MarkdownContributions
|
||||
): vscode.Uri[] {
|
||||
const baseRoots = contributions.previewResourceRoots;
|
||||
|
||||
const folder = vscode.workspace.getWorkspaceFolder(resource);
|
||||
if (folder) {
|
||||
@@ -266,6 +327,7 @@ export class MarkdownPreview {
|
||||
}
|
||||
|
||||
private onDidScrollPreview(line: number) {
|
||||
this.line = line;
|
||||
for (const editor of vscode.window.visibleTextEditors) {
|
||||
if (!this.isPreviewOf(editor.document.uri)) {
|
||||
continue;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isMarkdownFile } from '../util/file';
|
||||
import { MarkdownPreviewConfigurationManager } from './previewConfig';
|
||||
import { MarkdownContributions } from '../markdownExtensions';
|
||||
|
||||
export class MarkdownPreviewManager {
|
||||
export class MarkdownPreviewManager implements vscode.WebviewSerializer {
|
||||
private static readonly markdownPreviewActiveContextKey = 'markdownPreviewFocus';
|
||||
|
||||
private readonly topmostLineMonitor = new MarkdownFileTopmostLineMonitor();
|
||||
@@ -29,15 +29,14 @@ export class MarkdownPreviewManager {
|
||||
private readonly contributions: MarkdownContributions
|
||||
) {
|
||||
vscode.window.onDidChangeActiveTextEditor(editor => {
|
||||
if (editor) {
|
||||
if (isMarkdownFile(editor.document)) {
|
||||
for (const preview of this.previews.filter(preview => !preview.locked)) {
|
||||
preview.update(editor.document.uri);
|
||||
}
|
||||
if (editor && isMarkdownFile(editor.document)) {
|
||||
for (const preview of this.previews.filter(preview => !preview.locked)) {
|
||||
preview.update(editor.document.uri);
|
||||
}
|
||||
}
|
||||
}, null, this.disposables);
|
||||
|
||||
this.disposables.push(vscode.window.registerWebviewSerializer(MarkdownPreview.viewType, this));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -66,7 +65,6 @@ export class MarkdownPreviewManager {
|
||||
preview.reveal(previewSettings.previewColumn);
|
||||
} else {
|
||||
preview = this.createNewPreview(resource, previewSettings);
|
||||
this.previews.push(preview);
|
||||
}
|
||||
|
||||
preview.update(resource);
|
||||
@@ -90,6 +88,30 @@ export class MarkdownPreviewManager {
|
||||
}
|
||||
}
|
||||
|
||||
public async deserializeWebview(
|
||||
webview: vscode.Webview,
|
||||
state: any
|
||||
): Promise<boolean> {
|
||||
const preview = MarkdownPreview.revive(
|
||||
webview,
|
||||
state,
|
||||
this.contentProvider,
|
||||
this.previewConfigurations,
|
||||
this.logger,
|
||||
this.topmostLineMonitor);
|
||||
|
||||
this.registerPreview(preview);
|
||||
preview.refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async serializeWebview(
|
||||
webview: vscode.Webview,
|
||||
): Promise<any> {
|
||||
const preview = this.previews.find(preview => preview.isWebviewOf(webview));
|
||||
return preview ? preview.state : undefined;
|
||||
}
|
||||
|
||||
private getExistingPreview(
|
||||
resource: vscode.Uri,
|
||||
previewSettings: PreviewSettings
|
||||
@@ -101,8 +123,8 @@ export class MarkdownPreviewManager {
|
||||
private createNewPreview(
|
||||
resource: vscode.Uri,
|
||||
previewSettings: PreviewSettings
|
||||
) {
|
||||
const preview = new MarkdownPreview(
|
||||
): MarkdownPreview {
|
||||
const preview = MarkdownPreview.create(
|
||||
resource,
|
||||
previewSettings.previewColumn,
|
||||
previewSettings.locked,
|
||||
@@ -112,6 +134,14 @@ export class MarkdownPreviewManager {
|
||||
this.topmostLineMonitor,
|
||||
this.contributions);
|
||||
|
||||
return this.registerPreview(preview);
|
||||
}
|
||||
|
||||
private registerPreview(
|
||||
preview: MarkdownPreview
|
||||
): MarkdownPreview {
|
||||
this.previews.push(preview);
|
||||
|
||||
preview.onDispose(() => {
|
||||
const existing = this.previews.indexOf(preview!);
|
||||
if (existing >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user