2020-10-03 18:04:18 +00:00
|
|
|
/**
|
2020-10-24 21:45:32 +00:00
|
|
|
* context/preview.ts
|
2020-10-03 18:04:18 +00:00
|
|
|
*
|
|
|
|
* @author CismonX <admin@cismon.net>
|
|
|
|
* @license MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
import * as path from 'path';
|
2020-10-04 17:26:21 +00:00
|
|
|
import * as vscode from 'vscode';
|
2020-10-24 21:45:32 +00:00
|
|
|
import DocumentContext from './document';
|
|
|
|
import ContextMapping from '../context_mapping';
|
|
|
|
import Diagnosis from '../diagnosis';
|
|
|
|
import Logger from '../logger';
|
|
|
|
import Options from '../options';
|
|
|
|
import Converter from '../utils/converter';
|
|
|
|
import { prompt } from '../utils/misc';
|
|
|
|
import { Operator, Optional } from '../utils/types';
|
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
|
|
|
|
|
|
|
/**
|
|
|
|
* Create (if not yet created) and show preview for a Texinfo document.
|
|
|
|
*
|
|
|
|
* @param editor The editor where the document is being held.
|
|
|
|
*/
|
2020-10-24 21:45:32 +00:00
|
|
|
static async showPreview(editor: vscode.TextEditor) {
|
2020-10-03 18:04:18 +00:00
|
|
|
const document = editor.document;
|
2020-10-22 22:40:41 +00:00
|
|
|
// Only show preview for saved files, as we're not gonna send document content to `makeinfo` via STDIN.
|
|
|
|
// Instead, the file will be loaded from disk.
|
2020-10-03 18:04:18 +00:00
|
|
|
if (document.isUntitled) {
|
2020-10-22 22:40:41 +00:00
|
|
|
if (!await prompt('Save this document to display preview.', 'Save')) return;
|
2020-10-20 20:07:44 +00:00
|
|
|
if (!await document.save()) return;
|
2020-10-03 18:04:18 +00:00
|
|
|
}
|
2020-10-24 21:45:32 +00:00
|
|
|
ContextMapping.getDocumentContext(document).initPreview().panel.reveal();
|
2020-10-03 18:04:18 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 20:07:44 +00:00
|
|
|
private readonly document = this.documentContext.document;
|
2020-10-03 18:04:18 +00:00
|
|
|
|
|
|
|
private readonly panel: vscode.WebviewPanel;
|
|
|
|
|
2020-10-04 12:40:54 +00:00
|
|
|
private readonly disposables = <vscode.Disposable[]>[];
|
2020-10-03 18:04:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the preview is updating.
|
|
|
|
*/
|
|
|
|
private updating = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether a preview update request is pending.
|
|
|
|
*/
|
|
|
|
private pendingUpdate = false;
|
|
|
|
|
2020-10-20 20:07:44 +00:00
|
|
|
close() {
|
|
|
|
this.disposables.forEach(event => event.dispose());
|
2020-10-03 18:04:18 +00:00
|
|
|
this.panel.dispose();
|
2020-10-20 20:07:44 +00:00
|
|
|
this.documentContext.closePreview();
|
2020-10-24 15:51:44 +00:00
|
|
|
// Only show diagnostic information when the preview is active.
|
2020-10-24 21:45:32 +00:00
|
|
|
Diagnosis.delete(this.document);
|
2020-10-03 18:04:18 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 20:07:44 +00:00
|
|
|
async updateWebview() {
|
2020-10-03 18:04:18 +00:00
|
|
|
if (this.updating) {
|
|
|
|
this.pendingUpdate = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.updating = true;
|
|
|
|
this.pendingUpdate = false;
|
2020-10-22 22:40:41 +00:00
|
|
|
// Inform the user that the preview is updating if `makeinfo` takes too long.
|
|
|
|
setTimeout(() => this.updating && this.updateTitle(), 500);
|
2020-10-24 21:45:32 +00:00
|
|
|
const { data, error } = await new Converter(this.document.fileName, this.imageTransformer).convert();
|
2020-10-24 15:51:44 +00:00
|
|
|
if (error) {
|
2020-10-24 21:45:32 +00:00
|
|
|
Logger.log(error);
|
|
|
|
Diagnosis.update(this.document, error);
|
|
|
|
} else {
|
|
|
|
Diagnosis.delete(this.document);
|
2020-10-24 15:51:44 +00:00
|
|
|
}
|
|
|
|
if (data === undefined) {
|
2020-10-22 22:37:47 +00:00
|
|
|
prompt(`Failed to show preview for ${this.document.fileName}.`, 'Show log', true)
|
2020-10-24 21:45:32 +00:00
|
|
|
.then(result => result && Logger.show());
|
2020-10-03 18:04:18 +00:00
|
|
|
} else {
|
2020-10-24 15:51:44 +00:00
|
|
|
this.panel.webview.html = data;
|
2020-10-03 18:04:18 +00:00
|
|
|
}
|
|
|
|
this.updating = false;
|
2020-10-04 12:40:54 +00:00
|
|
|
this.updateTitle();
|
2020-10-15 20:16:13 +00:00
|
|
|
this.pendingUpdate && this.updateWebview();
|
2020-10-03 18:04:18 +00:00
|
|
|
}
|
2020-10-24 21:45:32 +00:00
|
|
|
|
|
|
|
constructor(private readonly documentContext: DocumentContext) {
|
|
|
|
this.panel = vscode.window.createWebviewPanel('texinfo.preview', '', vscode.ViewColumn.Beside,
|
|
|
|
{ enableFindWidget: true, retainContextWhenHidden: true, enableScripts: true });
|
|
|
|
this.disposables.push(this.panel.onDidDispose(() => this.close()));
|
|
|
|
this.updateTitle();
|
|
|
|
this.updateWebview();
|
|
|
|
}
|
|
|
|
|
|
|
|
private get imageTransformer(): Optional<Operator<string>> {
|
|
|
|
if (!Options.displayImage) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
const pathName = path.dirname(this.document.fileName);
|
|
|
|
return src => {
|
|
|
|
const srcUri = vscode.Uri.file(pathName + '/' + src);
|
|
|
|
// To display images in webviews, image URIs in HTML should be converted to VSCode-recognizable ones.
|
|
|
|
return this.panel.webview.asWebviewUri(srcUri).toString();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private updateTitle() {
|
|
|
|
const updating = this.updating ? '(Updating) ' : '';
|
|
|
|
const fileName = path.basename(this.document.fileName);
|
|
|
|
this.panel.title = `${updating}Preview ${fileName}`;
|
|
|
|
}
|
2020-10-03 18:04:18 +00:00
|
|
|
}
|