Update
This commit is contained in:
parent
4cbbcdfd4d
commit
c52c7b5924
|
@ -35,7 +35,7 @@ See `File -> Preferences -> Settings -> Extensions -> Texinfo` for details. The
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
* If syntax highlighting is not satisfactory, try another color theme where keyword/operator colors are distinct (e.g. Solarized Light/Dark, Monokai).
|
* If syntax highlighting is not satisfactory, try another color theme (e.g. Solarized Light/Dark, Monokai) where keyword/operator colors are distinct.
|
||||||
* Preview content is updated on document save rather than document change.
|
* Preview content is updated on document save rather than document change.
|
||||||
* For macOS users: Preinstalled GNU Texinfo distribution is very old. Use a latest one instead. This can be easily done by `brew install texinfo` and change extension setting `texinfo.makeinfo` value.
|
* For macOS users: Preinstalled GNU Texinfo distribution is very old. Use a latest one instead. This can be easily done by `brew install texinfo` and change extension setting `texinfo.makeinfo` value.
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@eslint/eslintrc": {
|
"@eslint/eslintrc": {
|
||||||
"version": "0.1.3",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.0.tgz",
|
||||||
"integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
|
"integrity": "sha512-+cIGPCBdLCzqxdtwppswP+zTsH9BOIGzAeKfBIbtb4gW/giMlfMwP0HUSFfhzh20f9u8uZ8hOp62+4GPquTbwQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
|
@ -74,9 +74,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.11.10",
|
"version": "14.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.10.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.2.tgz",
|
||||||
"integrity": "sha512-yV1nWZPlMFpoXyoknm4S56y2nlTAuFYaJuQtYRAOU7xA/FJ9RY0Xm7QOkaYMMmr8ESdHIuUb6oQgR/0+2NqlyA==",
|
"integrity": "sha512-jeYJU2kl7hL9U5xuI/BhKPZ4vqGM/OmK6whiFAXVhlstzZhVamWhDSmHyGLIp+RVyuF9/d0dqr2P85aFj4BvJg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/vscode": {
|
"@types/vscode": {
|
||||||
|
@ -169,9 +169,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "6.12.5",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
@ -403,13 +403,13 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"eslint": {
|
"eslint": {
|
||||||
"version": "7.11.0",
|
"version": "7.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.12.0.tgz",
|
||||||
"integrity": "sha512-G9+qtYVCHaDi1ZuWzBsOWo2wSwd70TXnU6UHA3cTYHp7gCTXZcpggWFoUVAMRarg68qtPoNfFbzPh+VdOgmwmw==",
|
"integrity": "sha512-n5pEU27DRxCSlOhJ2rO57GDLcNsxO0LPpAbpFdh7xmcDmjmlGUfoyrsB3I7yYdQXO5N3gkSTiDrPSPNFiiirXA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.0.0",
|
"@babel/code-frame": "^7.0.0",
|
||||||
"@eslint/eslintrc": "^0.1.3",
|
"@eslint/eslintrc": "^0.2.0",
|
||||||
"ajv": "^6.10.0",
|
"ajv": "^6.10.0",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
"cross-spawn": "^7.0.2",
|
"cross-spawn": "^7.0.2",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "texinfo",
|
"name": "texinfo",
|
||||||
"displayName": "Texinfo Language Support",
|
"displayName": "Texinfo Language Support",
|
||||||
"description": "Syntax highlighting, code completion and preview support for Texinfo.",
|
"description": "Syntax highlighting, code completion, folding and preview support for Texinfo.",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "CismonX",
|
"name": "CismonX",
|
||||||
|
@ -15,12 +15,12 @@
|
||||||
},
|
},
|
||||||
"icon": "assets/texinfo.png",
|
"icon": "assets/texinfo.png",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^14.11.10",
|
"@types/node": "^14.14.2",
|
||||||
"@types/vscode": "^1.50.0",
|
"@types/vscode": "^1.50.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^3.8.0",
|
"@typescript-eslint/eslint-plugin": "^3.8.0",
|
||||||
"@typescript-eslint/parser": "^3.8.0",
|
"@typescript-eslint/parser": "^3.8.0",
|
||||||
"cson": "^7.20.0",
|
"cson": "^7.20.0",
|
||||||
"eslint": "^7.11.0",
|
"eslint": "^7.12.0",
|
||||||
"language-texinfo": "^1.0.0",
|
"language-texinfo": "^1.0.0",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
|
@ -128,7 +128,7 @@
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 100,
|
"default": 100,
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"markdownDescription": "Max tolerated number of errors when trying to display preview.\n\nThis corresponds to the `--error-limit=NUM` option of `makeinfo`."
|
"markdownDescription": "Max number of errors before quit when trying to display preview.\n\nThis corresponds to the `--error-limit=NUM` option of `makeinfo`."
|
||||||
},
|
},
|
||||||
"texinfo.preview.force": {
|
"texinfo.preview.force": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|
|
@ -17,7 +17,6 @@ export default class Converter {
|
||||||
* Convert a Texinfo document to HTML.
|
* Convert a Texinfo document to HTML.
|
||||||
*
|
*
|
||||||
* @param path Path to the Texinfo document.
|
* @param path Path to the Texinfo document.
|
||||||
* @returns HTML code, or `undefined` if conversion fails.
|
|
||||||
*/
|
*/
|
||||||
static async convertToHtml(path: string) {
|
static async convertToHtml(path: string) {
|
||||||
return await new Converter().convert(path);
|
return await new Converter().convert(path);
|
||||||
|
|
|
@ -32,7 +32,7 @@ export default class Document {
|
||||||
static update(event: vscode.TextDocumentChangeEvent) {
|
static update(event: vscode.TextDocumentChangeEvent) {
|
||||||
const documentContext = Document.get(event.document);
|
const documentContext = Document.get(event.document);
|
||||||
if (documentContext?.foldingRange.update(event.contentChanges)) {
|
if (documentContext?.foldingRange.update(event.contentChanges)) {
|
||||||
documentContext.symbol.update(documentContext.foldingRange.values);
|
documentContext.symbol.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,18 +14,10 @@ export default class Logger {
|
||||||
|
|
||||||
private static singleton?: Logger;
|
private static singleton?: Logger;
|
||||||
|
|
||||||
private static get instance() {
|
static get instance() {
|
||||||
return Logger.singleton ??= new Logger();
|
return Logger.singleton ??= new Logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
static log(message: string) {
|
|
||||||
Logger.instance.log(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
static show() {
|
|
||||||
Logger.instance.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
static destroy() {
|
static destroy() {
|
||||||
Logger.instance.outputChannel.dispose();
|
Logger.instance.outputChannel.dispose();
|
||||||
Logger.singleton = undefined;
|
Logger.singleton = undefined;
|
||||||
|
@ -37,12 +29,12 @@ export default class Logger {
|
||||||
this.outputChannel = vscode.window.createOutputChannel('Texinfo');
|
this.outputChannel = vscode.window.createOutputChannel('Texinfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
private log(message: string) {
|
log(message: string) {
|
||||||
const dateTime = new Date().toLocaleString(undefined, { hour12: false });
|
const dateTime = new Date().toLocaleString(undefined, { hour12: false });
|
||||||
this.outputChannel.appendLine(`[ ${dateTime} ]:\n${message}`);
|
this.outputChannel.appendLine(`[ ${dateTime} ]\n${message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private show() {
|
show() {
|
||||||
this.outputChannel.show(true);
|
this.outputChannel.show(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,8 @@ export default class Preview {
|
||||||
private pendingUpdate = false;
|
private pendingUpdate = false;
|
||||||
|
|
||||||
constructor(private readonly documentContext: Document) {
|
constructor(private readonly documentContext: Document) {
|
||||||
this.panel = vscode.window.createWebviewPanel('texinfo.preview', '', vscode.ViewColumn.Beside);
|
this.panel = vscode.window.createWebviewPanel('texinfo.preview', '', vscode.ViewColumn.Beside,
|
||||||
|
{ enableFindWidget: true, retainContextWhenHidden: true });
|
||||||
this.disposables.push(this.panel.onDidDispose(() => this.close()));
|
this.disposables.push(this.panel.onDidDispose(() => this.close()));
|
||||||
this.updateTitle();
|
this.updateTitle();
|
||||||
this.updateWebview();
|
this.updateWebview();
|
||||||
|
|
|
@ -29,53 +29,47 @@ export class DocumentSymbolContext {
|
||||||
|
|
||||||
private symbols?: vscode.DocumentSymbol[];
|
private symbols?: vscode.DocumentSymbol[];
|
||||||
|
|
||||||
private foldingRanges?: FoldingRange[];
|
private foldingRanges?: readonly FoldingRange[];
|
||||||
|
|
||||||
get values() {
|
get values() {
|
||||||
return this.symbols ??= this.calculcateDocumentSymbols();
|
return this.symbols ??= this.calculcateDocumentSymbols();
|
||||||
}
|
}
|
||||||
|
|
||||||
update(foldingRanges: FoldingRange[]) {
|
clear() {
|
||||||
this.foldingRanges = foldingRanges;
|
this.foldingRanges = undefined;
|
||||||
this.symbols = undefined;
|
this.symbols = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate (very limited) document symbols based on folding ranges.
|
* Calculate document symbols based on folding ranges.
|
||||||
*/
|
*/
|
||||||
private calculcateDocumentSymbols() {
|
private calculcateDocumentSymbols() {
|
||||||
this.symbols = [];
|
|
||||||
if (this.foldingRanges === undefined) {
|
|
||||||
this.foldingRanges = this.documentContext.foldingRange.values;
|
|
||||||
}
|
|
||||||
const ranges = Array<RangeNode>(this.document.lineCount);
|
const ranges = Array<RangeNode>(this.document.lineCount);
|
||||||
this.foldingRanges.forEach(range => {
|
(this.foldingRanges ??= this.documentContext.foldingRange.values)
|
||||||
if (range.kind !== undefined) return;
|
.forEach(range => range.kind ?? (ranges[range.start] = range));
|
||||||
ranges[range.start] = range;
|
return this.symbols = foldingRangeToSymbols(ranges, 0, ranges.length);
|
||||||
});
|
|
||||||
return this.symbols = this.rangeToSymbols(ranges, 0, ranges.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private rangeToSymbols(ranges: RangeNode[], start: number, end: number) {
|
|
||||||
const symbols = <vscode.DocumentSymbol[]>[];
|
|
||||||
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 symbol = new vscode.DocumentSymbol('@' + node.name, node.detail,
|
|
||||||
vscode.SymbolKind.String, range, selectionRange);
|
|
||||||
symbol.children = this.rangeToSymbols(ranges, idx + 1, node.end);
|
|
||||||
symbols.push(symbol);
|
|
||||||
idx = node.end;
|
|
||||||
}
|
|
||||||
return symbols;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private readonly documentContext: Document) {}
|
constructor(private readonly documentContext: Document) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RangeNode = Optional<FoldingRange>;
|
type RangeNode = Optional<FoldingRange>;
|
||||||
|
|
||||||
|
function foldingRangeToSymbols(ranges: readonly RangeNode[], start: number, end: number) {
|
||||||
|
const symbols = <vscode.DocumentSymbol[]>[];
|
||||||
|
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 symbol = new vscode.DocumentSymbol('@' + node.name, node.detail,
|
||||||
|
vscode.SymbolKind.String, range, selectionRange);
|
||||||
|
symbol.children = foldingRangeToSymbols(ranges, idx + 1, node.end);
|
||||||
|
symbols.push(symbol);
|
||||||
|
idx = node.end;
|
||||||
|
}
|
||||||
|
return symbols;
|
||||||
|
}
|
||||||
|
|
11
src/utils.ts
11
src/utils.ts
|
@ -8,7 +8,6 @@
|
||||||
import * as child_process from 'child_process';
|
import * as child_process from 'child_process';
|
||||||
import * as htmlparser from 'node-html-parser';
|
import * as htmlparser from 'node-html-parser';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import Logger from './logger';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a prompt with two buttons, "Confirm" and "Cancel", and wait for user action.
|
* Open a prompt with two buttons, "Confirm" and "Cancel", and wait for user action.
|
||||||
|
@ -32,14 +31,12 @@ export async function prompt(message: string, confirm: string, error = false) {
|
||||||
* @returns The output data, or `undefined` if execution fails.
|
* @returns The output data, or `undefined` if execution fails.
|
||||||
*/
|
*/
|
||||||
export function exec(path: string, args: string[], maxBuffer: number) {
|
export function exec(path: string, args: string[], maxBuffer: number) {
|
||||||
return new Promise<Optional<string>>(resolve => {
|
return new Promise<ExecResult>(resolve => {
|
||||||
child_process.execFile(path, args, { maxBuffer: maxBuffer }, (error, stdout, stderr) => {
|
child_process.execFile(path, args, { maxBuffer: maxBuffer }, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
Logger.log(stderr ? stderr : error.message);
|
resolve({ error: stderr ? stderr : error.message });
|
||||||
resolve(undefined);
|
|
||||||
} else {
|
} else {
|
||||||
stderr && Logger.log(stderr);
|
resolve({ data: stdout, error: stderr });
|
||||||
resolve(stdout);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -65,4 +62,6 @@ export function transformHtmlImageUri(htmlCode: string, transformer: (src: strin
|
||||||
|
|
||||||
export type Optional<T> = T | undefined;
|
export type Optional<T> = T | undefined;
|
||||||
|
|
||||||
|
export type ExecResult = { data?: string, error: string };
|
||||||
|
|
||||||
export type Range = { start: number, end: number };
|
export type Range = { start: number, end: number };
|
||||||
|
|
Loading…
Reference in New Issue