vscode-texinfo/src/contexts/preview.ts

128 lines
4.6 KiB
TypeScript
Raw Normal View History

2020-10-03 18:04:18 +00:00
/**
2020-10-25 18:14:13 +00:00
* contexts/preview.ts
2021-03-16 12:01:13 +00:00
*
* Copyright (C) 2020,2021 CismonX <admin@cismon.net>
*
* This file is part of vscode-texinfo.
*
* vscode-texinfo is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* vscode-texinfo is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along with
* vscode-texinfo. If not, see <https://www.gnu.org/licenses/>.
2020-10-03 18:04:18 +00:00
*/
import * as path from 'path';
import * as vscode from 'vscode';
2020-10-24 21:45:32 +00:00
import DocumentContext from './document';
import Converter from '../utils/converter';
2020-11-11 12:29:30 +00:00
import { getNodeHtmlRef, prompt } from '../utils/misc';
2020-10-03 18:04:18 +00:00
/**
2020-10-24 21:45:32 +00:00
* Stores information of a Texinfo document preview.
2020-10-03 18:04:18 +00:00
*/
2020-10-24 21:45:32 +00:00
export default class PreviewContext {
2020-10-03 18:04:18 +00:00
2021-04-19 12:43:20 +00:00
close() {
2021-05-25 04:16:56 +00:00
this._disposables.forEach(event => event.dispose());
this._panel.dispose();
this._documentContext.closePreview();
2021-04-19 12:43:20 +00:00
// Only show diagnostic information when the preview is active.
2021-05-25 04:16:56 +00:00
this._diagnosis.delete(this._document);
2021-04-19 12:43:20 +00:00
}
goto(nodeName: string) {
2021-05-25 04:16:56 +00:00
this._panel.webview.postMessage({ command: 'goto', value: getNodeHtmlRef(nodeName) });
2021-04-19 12:43:20 +00:00
}
show() {
2021-05-25 04:16:56 +00:00
this._panel.reveal();
2021-04-19 12:43:20 +00:00
}
async updateWebview() {
2021-05-25 04:16:56 +00:00
if (this._updating) {
this._pendingUpdate = true;
2021-04-19 12:43:20 +00:00
return;
2020-10-03 18:04:18 +00:00
}
2021-05-25 04:16:56 +00:00
this._updating = true;
this._pendingUpdate = false;
2021-04-19 12:43:20 +00:00
// Inform the user that the preview is updating if `makeinfo` takes too long.
2021-05-25 04:16:56 +00:00
setTimeout(() => this._updating && this._updateTitle(), 500);
const initFile = this._globalContext.extensionPath + '/ext/html-preview.pm';
const converter = new Converter(this._document.fileName, initFile, this._globalContext.options, this._logger);
const { data, error } = await converter.toHTML(path => this._panel.webview.asWebviewUri(path), this._script);
2021-04-19 12:43:20 +00:00
if (error) {
2021-05-25 04:16:56 +00:00
this._logger.log(error);
this._diagnosis.update(this._document, error);
2021-04-19 12:43:20 +00:00
} else {
2021-05-25 04:16:56 +00:00
this._diagnosis.delete(this._document);
2021-04-19 12:43:20 +00:00
}
if (data === undefined) {
2021-05-25 04:16:56 +00:00
prompt(`Failed to show preview for ${this._document.fileName}.`, 'Show log', true)
.then(result => result && this._logger.show());
2021-04-19 12:43:20 +00:00
} else {
2021-05-25 04:16:56 +00:00
this._panel.webview.html = data;
2021-04-19 12:43:20 +00:00
}
2021-05-25 04:16:56 +00:00
this._updating = false;
this._updateTitle();
this._pendingUpdate && this.updateWebview();
2020-10-03 18:04:18 +00:00
}
2021-05-25 04:16:56 +00:00
constructor(private readonly _documentContext: DocumentContext) {
this._panel = vscode.window.createWebviewPanel('texinfo.preview', '', vscode.ViewColumn.Beside,
2021-04-19 12:43:20 +00:00
{ enableFindWidget: true, retainContextWhenHidden: true, enableScripts: true });
2021-05-25 04:16:56 +00:00
this._disposables.push(this._panel.onDidDispose(() => this.close()));
this._updateTitle();
2021-04-19 12:43:20 +00:00
this.updateWebview();
2020-11-11 12:29:30 +00:00
}
2021-05-25 04:16:56 +00:00
private readonly _document = this._documentContext.document;
private readonly _globalContext = this._documentContext.globalContext;
private readonly _diagnosis = this._globalContext.diagnosis;
private readonly _logger = this._globalContext.logger;
2020-10-03 18:04:18 +00:00
2021-05-25 04:16:56 +00:00
private readonly _disposables = <vscode.Disposable[]>[];
2020-10-03 18:04:18 +00:00
2021-05-25 04:16:56 +00:00
private readonly _panel: vscode.WebviewPanel;
2020-10-03 18:04:18 +00:00
/**
* Whether a preview update request is pending.
*/
2021-05-25 04:16:56 +00:00
private _pendingUpdate = false;
2020-10-03 18:04:18 +00:00
2021-04-19 12:43:20 +00:00
/**
* Whether the preview is updating.
*/
2021-05-25 04:16:56 +00:00
private _updating = false;
2021-04-19 12:43:20 +00:00
2021-04-22 09:07:13 +00:00
/**
* Generate script used for jumping to the corresponding location of preview with code lens.
*/
2021-05-25 04:16:56 +00:00
private get _script() {
if (!this._globalContext.options.enableCodeLens) return undefined;
2021-03-15 12:43:38 +00:00
return "window.addEventListener('message', event => {" +
"const message = event.data;" +
"switch (message.command) {" +
"case 'goto':" +
"window.location.hash = message.value;" +
// We may want to scroll to the same node again.
"history.pushState('', '', window.location.pathname);" +
"break;" +
"}" +
"})";
}
2021-05-25 04:16:56 +00:00
private _updateTitle() {
const updating = this._updating ? '(Updating) ' : '';
const fileName = path.basename(this._document.fileName);
this._panel.title = `${updating}Preview ${fileName}`;
2020-10-24 21:45:32 +00:00
}
2020-10-03 18:04:18 +00:00
}