Implement diagnosis.
This commit is contained in:
parent
c52c7b5924
commit
2c5aec48ed
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* diagnosis.ts
|
||||
*
|
||||
* @author CismonX <admin@cismon.net>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { isDefined, lineNumToRange } from './utils';
|
||||
|
||||
/**
|
||||
* Manage diagnostic information of Texinfo documents.
|
||||
*/
|
||||
export default class Diagnosis implements vscode.Disposable {
|
||||
|
||||
private static singleton?: Diagnosis;
|
||||
|
||||
static get instance() {
|
||||
return Diagnosis.singleton ??= new Diagnosis();
|
||||
}
|
||||
|
||||
private readonly diagnostics = vscode.languages.createDiagnosticCollection('texinfo');
|
||||
|
||||
dispose() {
|
||||
this.diagnostics.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate diagnostic information based on error log from `makeinfo`.
|
||||
*
|
||||
* @param document
|
||||
* @param logText
|
||||
*/
|
||||
update(document: vscode.TextDocument, logText: string) {
|
||||
const fileName = document.uri.path;
|
||||
const diagnostics = logText.split('\n').filter(line => line.startsWith(fileName))
|
||||
.map(line => logLineToDiagnostic(line.substring(fileName.length + 1))).filter(isDefined);
|
||||
this.diagnostics.set(document.uri, diagnostics);
|
||||
}
|
||||
|
||||
delete(document: vscode.TextDocument) {
|
||||
this.diagnostics.delete(document.uri);
|
||||
}
|
||||
}
|
||||
|
||||
function logLineToDiagnostic(lineText: string) {
|
||||
const lineNum = Number.parseInt(lineText) - 1;
|
||||
// Ignore error that does not correspond a line.
|
||||
if (Number.isNaN(lineNum)) return undefined;
|
||||
const message = lineText.substring(lineNum.toString().length + 2);
|
||||
const severity = message.startsWith('warning:') ? vscode.DiagnosticSeverity.Warning : undefined;
|
||||
return new vscode.Diagnostic(lineNumToRange(lineNum), message, severity);
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import Diagnosis from './diagnosis';
|
||||
import Document from './document';
|
||||
import Logger from './logger';
|
||||
import Options from './options';
|
||||
|
@ -25,6 +26,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
vscode.languages.registerCompletionItemProvider('texinfo', new CompletionItemProvider(), '@'),
|
||||
vscode.languages.registerFoldingRangeProvider('texinfo', new FoldingRangeProvider()),
|
||||
vscode.languages.registerDocumentSymbolProvider('texinfo', new DocumentSymbolProvider()),
|
||||
Diagnosis.instance,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import Converter from './converter';
|
||||
import Diagnosis from './diagnosis';
|
||||
import Document from './document';
|
||||
import Logger from './logger';
|
||||
import Options from './options';
|
||||
|
@ -70,6 +71,8 @@ export default class Preview {
|
|||
this.disposables.forEach(event => event.dispose());
|
||||
this.panel.dispose();
|
||||
this.documentContext.closePreview();
|
||||
// Only show diagnostic information when the preview is active.
|
||||
Diagnosis.instance.delete(this.document);
|
||||
}
|
||||
|
||||
async updateWebview() {
|
||||
|
@ -81,20 +84,23 @@ export default class Preview {
|
|||
this.pendingUpdate = false;
|
||||
// Inform the user that the preview is updating if `makeinfo` takes too long.
|
||||
setTimeout(() => this.updating && this.updateTitle(), 500);
|
||||
let htmlCode = await Converter.convertToHtml(this.document.fileName);
|
||||
if (htmlCode === undefined) {
|
||||
const { data, error } = await Converter.convertToHtml(this.document.fileName);
|
||||
if (error) {
|
||||
Logger.instance.log(error);
|
||||
Diagnosis.instance.update(this.document, error);
|
||||
}
|
||||
if (data === undefined) {
|
||||
prompt(`Failed to show preview for ${this.document.fileName}.`, 'Show log', true)
|
||||
.then(result => result && Logger.show());
|
||||
.then(result => result && Logger.instance.show());
|
||||
} else if (Options.displayImage) {
|
||||
const pathName = path.dirname(this.document.fileName);
|
||||
// To display images in webviews, image URIs in HTML should be converted to VSCode-recognizable ones.
|
||||
this.panel.webview.html = transformHtmlImageUri(data, src => {
|
||||
const srcUri = vscode.Uri.file(pathName + '/' + src);
|
||||
return this.panel.webview.asWebviewUri(srcUri).toString();
|
||||
});
|
||||
} else {
|
||||
if (Options.displayImage) {
|
||||
const pathName = path.dirname(this.document.fileName);
|
||||
// To display images in webviews, image URIs in HTML should be converted to VSCode-recognizable ones.
|
||||
htmlCode = transformHtmlImageUri(htmlCode, src => {
|
||||
const srcUri = vscode.Uri.file(pathName + '/' + src);
|
||||
return this.panel.webview.asWebviewUri(srcUri).toString();
|
||||
});
|
||||
}
|
||||
this.panel.webview.html = htmlCode;
|
||||
this.panel.webview.html = data;
|
||||
}
|
||||
this.updating = false;
|
||||
this.updateTitle();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import * as vscode from 'vscode';
|
||||
import Document from './document';
|
||||
import { FoldingRange } from './folding';
|
||||
import { Optional } from './utils';
|
||||
import { lineNumToRange, Optional } from './utils';
|
||||
|
||||
/**
|
||||
* Provide document symbol information for Texinfo documents.
|
||||
|
@ -60,11 +60,8 @@ function foldingRangeToSymbols(ranges: readonly RangeNode[], start: number, end:
|
|||
for (let idx = start; idx < end; ++idx) {
|
||||
const node = ranges[idx];
|
||||
if (node === undefined) continue;
|
||||
const startPosition = new vscode.Position(idx, 0);
|
||||
const endFirstLine = new vscode.Position(idx, Number.MAX_SAFE_INTEGER);
|
||||
const endLastLine = new vscode.Position(node.end, Number.MAX_SAFE_INTEGER);
|
||||
const range = new vscode.Range(startPosition, endLastLine);
|
||||
const selectionRange = new vscode.Range(startPosition, endFirstLine);
|
||||
const range = lineNumToRange(idx, node.end);
|
||||
const selectionRange = lineNumToRange(idx);
|
||||
const symbol = new vscode.DocumentSymbol('@' + node.name, node.detail,
|
||||
vscode.SymbolKind.String, range, selectionRange);
|
||||
symbol.children = foldingRangeToSymbols(ranges, idx + 1, node.end);
|
||||
|
|
16
src/utils.ts
16
src/utils.ts
|
@ -60,6 +60,22 @@ export function transformHtmlImageUri(htmlCode: string, transformer: (src: strin
|
|||
return elements.length === 0 ? htmlCode : dom.outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert line numbers to VSCode range.
|
||||
*
|
||||
* @param startLine
|
||||
* @param endLine Default to `startLine`.
|
||||
*/
|
||||
export function lineNumToRange(startLine: number, endLine = startLine) {
|
||||
const startPosition = new vscode.Position(startLine, 0);
|
||||
const endPosition = new vscode.Position(endLine, Number.MAX_SAFE_INTEGER);
|
||||
return new vscode.Range(startPosition, endPosition);
|
||||
}
|
||||
|
||||
export function isDefined<T>(value: T | undefined): value is T {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
export type Optional<T> = T | undefined;
|
||||
|
||||
export type ExecResult = { data?: string, error: string };
|
||||
|
|
Loading…
Reference in New Issue