initial commit
This commit is contained in:
commit
ac1872501c
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": "warn",
|
||||
"@typescript-eslint/semi": "warn",
|
||||
"curly": "warn",
|
||||
"eqeqeq": "warn",
|
||||
"no-throw-literal": "warn",
|
||||
"semi": "off"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
.vscode/
|
||||
node_modules
|
||||
out
|
||||
.vscode-test/
|
||||
*.vsix
|
|
@ -0,0 +1,11 @@
|
|||
os:
|
||||
- linux
|
||||
dist: bionic
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- node
|
||||
- lts/*
|
||||
|
||||
script:
|
||||
- npm run vscode:prepublish
|
|
@ -0,0 +1,10 @@
|
|||
.vscode/**
|
||||
.vscode-test/**
|
||||
out/test/**
|
||||
src/**
|
||||
.gitignore
|
||||
.yarnrc
|
||||
**/tsconfig.json
|
||||
**/.eslintrc.json
|
||||
**/*.map
|
||||
**/*.ts
|
|
@ -0,0 +1 @@
|
|||
# Change Log
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 CismonX <admin@cismon.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,15 @@
|
|||
# vscode-texinfo
|
||||
|
||||
Texinfo language support for Visual Studio Code.
|
||||
|
||||
## Features
|
||||
|
||||
**Warning**: This extension is in the early stage of development. **DO NOT USE**.
|
||||
|
||||
## Requirements
|
||||
|
||||
To enable the preview feature, the `makeinfo` command-line tool, which is a part of [GNU Texinfo](https://www.gnu.org/software/texinfo/), should be present on your system.
|
||||
|
||||
## Extension Settings
|
||||
|
||||
See VSCode settings for details.
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"comments": {
|
||||
"lineComment": "@c"
|
||||
},
|
||||
"brackets": [
|
||||
["{", "}"]
|
||||
],
|
||||
"autoClosingPairs": [
|
||||
["{", "}"]
|
||||
],
|
||||
"surroundingPairs": [
|
||||
["{", "}"]
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,129 @@
|
|||
{
|
||||
"name": "texinfo",
|
||||
"displayName": "Texinfo Language Support",
|
||||
"description": "Syntax highlighting, autocompletion and preview support for Texinfo.",
|
||||
"version": "0.1.0",
|
||||
"author": {
|
||||
"name": "CismonX",
|
||||
"email": "admin@cismon.net",
|
||||
"url": "https://cismon.net"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/CismonX/vscode-texinfo"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.49.0"
|
||||
},
|
||||
"categories": [
|
||||
"Linters",
|
||||
"Other",
|
||||
"Programming Languages",
|
||||
"Snippets"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"activationEvents": [
|
||||
"onLanguage:texinfo"
|
||||
],
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "texinfo.showPreview",
|
||||
"title": "Show preview (Texinfo)",
|
||||
"icon": "$(open-preview)"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"editor/title": [
|
||||
{
|
||||
"command": "texinfo.showPreview",
|
||||
"when": "editorLangId == texinfo",
|
||||
"group": "navigation"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "Texinfo",
|
||||
"properties": {
|
||||
"texinfo.makeinfo": {
|
||||
"type": "string",
|
||||
"default": "makeinfo",
|
||||
"markdownDescription": "Path to the `makeinfo` command."
|
||||
},
|
||||
"texinfo.preview.noHeaders": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "Suppress node separators in preview. See `makeinfo --help` for details."
|
||||
},
|
||||
"texinfo.preview.maxSize": {
|
||||
"type": "integer",
|
||||
"default": "2",
|
||||
"markdownDescription": "Max allowed size (in MiB) for the preview document."
|
||||
},
|
||||
"texinfo.preview.errorLimit": {
|
||||
"type": "integer",
|
||||
"default": 100,
|
||||
"markdownDescription": "Max tolerated number of errors when trying to display preview."
|
||||
},
|
||||
"texinfo.preview.force": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "Preserve preview even if errors."
|
||||
},
|
||||
"texinfo.preview.noValidate": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "Supress node cross-reference validation."
|
||||
},
|
||||
"texinfo.preview.noWarn": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"markdownDescription": "Suppress warnings."
|
||||
}
|
||||
}
|
||||
},
|
||||
"languages": [
|
||||
{
|
||||
"id": "texinfo",
|
||||
"aliases": [
|
||||
"Texinfo"
|
||||
],
|
||||
"extensions": [
|
||||
".texi",
|
||||
".texinfo",
|
||||
".txi"
|
||||
],
|
||||
"configuration": "./language-configuration.json"
|
||||
}
|
||||
],
|
||||
"grammars": [
|
||||
{
|
||||
"language": "texinfo",
|
||||
"scopeName": "text.texinfo",
|
||||
"path": "./out/texinfo.tmGrammar.json",
|
||||
"configuration": "./language-configuration.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run lint && npm run build",
|
||||
"compile": "tsc -p ./",
|
||||
"prepare": "sh ./scripts/prepare.sh",
|
||||
"build": "npm run prepare && npm run compile",
|
||||
"lint": "eslint src --ext ts",
|
||||
"watch": "tsc -watch -p ./"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.11.2",
|
||||
"@types/vscode": "^1.49.0",
|
||||
"@typescript-eslint/eslint-plugin": "^3.8.0",
|
||||
"@typescript-eslint/parser": "^3.8.0",
|
||||
"eslint": "^7.10.0",
|
||||
"typescript": "^4.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"cson": "^7.20.0",
|
||||
"language-texinfo": "^1.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Convert TextMate grammar from CSON to JSON (VSCode cannot recognize CSON ones).
|
||||
TMGRAMMAR_CSON=./node_modules/language-texinfo/grammars/texinfo.cson
|
||||
TMGRAMMAR_JSON=./out/texinfo.tmGrammar.json
|
||||
cson2json $TMGRAMMAR_CSON > $TMGRAMMAR_JSON
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* converter.ts
|
||||
*
|
||||
* @author CismonX <admin@cismon.net>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { Options } from './options';
|
||||
import { exec } from './utils';
|
||||
|
||||
/**
|
||||
* Texinfo to HTML converter.
|
||||
*/
|
||||
export class Converter {
|
||||
|
||||
/**
|
||||
* Convert a texinfo document to HTML.
|
||||
*
|
||||
* @param path Path to the Texinfo document to be converted.
|
||||
*/
|
||||
static async convert(path: string) {
|
||||
const converter = new Converter(path);
|
||||
return await converter.convert();
|
||||
}
|
||||
|
||||
/**
|
||||
* The options to be passed to the `makeinfo` command.
|
||||
*/
|
||||
private readonly options = ['-o', '-', '--no-split', '--html'];
|
||||
|
||||
private constructor(path: string) {
|
||||
if (Options.noHeaders) {
|
||||
this.options.push('--no-headers');
|
||||
}
|
||||
if (Options.force) {
|
||||
this.options.push('--force');
|
||||
}
|
||||
if (Options.noValidate) {
|
||||
this.options.push('--no-validate');
|
||||
}
|
||||
if (Options.noWarn) {
|
||||
this.options.push('--no-warn');
|
||||
}
|
||||
this.options.push(`--error-limit=${Options.errorLimit}`);
|
||||
this.options.push(path);
|
||||
}
|
||||
|
||||
private async convert() {
|
||||
const makeinfo = Options.makeinfo;
|
||||
const maxBuffer = Options.maxSize * 1024 * 1024;
|
||||
return await exec(makeinfo, this.options, maxBuffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* extension.ts - Texinfo extension entry
|
||||
*
|
||||
* @author CismonX <admin@cismon.net>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Preview } from './preview';
|
||||
import { Options } from './options';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
context.subscriptions.push(
|
||||
vscode.workspace.onDidSaveTextDocument(Preview.update),
|
||||
vscode.workspace.onDidCloseTextDocument(Preview.close),
|
||||
vscode.commands.registerTextEditorCommand('texinfo.showPreview', Preview.show));
|
||||
}
|
||||
|
||||
export function deactivate() {
|
||||
Preview.destroyAll();
|
||||
Options.clear();
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* options.ts
|
||||
*
|
||||
* @author CismonX <admin@cismon.net>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
let options: Options | undefined;
|
||||
|
||||
/**
|
||||
* Get extension options.
|
||||
*
|
||||
* See `contributes.configuration` of package.json for details.
|
||||
*/
|
||||
export class Options {
|
||||
|
||||
private static get instance() {
|
||||
if (options === undefined) {
|
||||
options = new Options('texinfo');
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
static clear() {
|
||||
options = undefined;
|
||||
}
|
||||
|
||||
static get makeinfo() {
|
||||
return Options.instance.getString('makeinfo');
|
||||
}
|
||||
|
||||
static get noHeaders() {
|
||||
return Options.instance.getBoolean('preview.noHeaders');
|
||||
}
|
||||
|
||||
static get maxSize() {
|
||||
return Options.instance.getNumber('preview.maxSize');
|
||||
}
|
||||
|
||||
static get errorLimit() {
|
||||
return Options.instance.getNumber('preview.errorLimit');
|
||||
}
|
||||
|
||||
static get force() {
|
||||
return Options.instance.getBoolean('preview.force');
|
||||
}
|
||||
|
||||
static get noValidate() {
|
||||
return Options.instance.getBoolean('preview.noValidate');
|
||||
}
|
||||
|
||||
static get noWarn() {
|
||||
return Options.instance.getBoolean('preview.noWarn');
|
||||
}
|
||||
|
||||
private readonly configuration: vscode.WorkspaceConfiguration;
|
||||
|
||||
private constructor(section: string) {
|
||||
this.configuration = vscode.workspace.getConfiguration(section);
|
||||
}
|
||||
|
||||
private getString(section: string) {
|
||||
return this.configuration.get<string>(section) ?? '';
|
||||
}
|
||||
|
||||
private getBoolean(section: string) {
|
||||
return this.configuration.get<boolean>(section) ?? false;
|
||||
}
|
||||
|
||||
private getNumber(section: string) {
|
||||
return this.configuration.get<number>(section) ?? 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* preview.ts
|
||||
*
|
||||
* @author CismonX <admin@cismon.net>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import { Converter } from './converter';
|
||||
import { prompt } from './utils';
|
||||
|
||||
/**
|
||||
* Texinfo document preview.
|
||||
*/
|
||||
export class Preview {
|
||||
|
||||
private static readonly map = new Map<vscode.TextDocument, Preview>();
|
||||
|
||||
/**
|
||||
* Create (if not yet created) and show preview for a Texinfo document.
|
||||
*
|
||||
* @param editor The editor where the document is being held.
|
||||
*/
|
||||
static async show(editor: vscode.TextEditor) {
|
||||
const document = editor.document;
|
||||
if (document.isUntitled) {
|
||||
if (!await prompt('Save this document to display preview.', 'Save')) {
|
||||
return;
|
||||
}
|
||||
if (!await document.save()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
(Preview.map.get(document) ?? new Preview(document)).panel.reveal();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the document has a corresponding Texinfo preview, update the preview.
|
||||
*
|
||||
* @param document
|
||||
*/
|
||||
static update(document: vscode.TextDocument) {
|
||||
Preview.getByDocument(document)?.updateWebview();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the document has a corresponding Texinfo preview, close the preview.
|
||||
*
|
||||
* @param document
|
||||
*/
|
||||
static close(document: vscode.TextDocument) {
|
||||
Preview.getByDocument(document)?.destroy();
|
||||
}
|
||||
|
||||
static destroyAll() {
|
||||
Preview.map.forEach((preview) => preview.destroy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get associated preview instance of the given document.
|
||||
*
|
||||
* @param document
|
||||
*/
|
||||
private static getByDocument(document: vscode.TextDocument) {
|
||||
return document.languageId !== 'texinfo' ? undefined : Preview.map.get(document);
|
||||
}
|
||||
|
||||
private readonly panel: vscode.WebviewPanel;
|
||||
|
||||
private readonly disposables = new Array<vscode.Disposable>();
|
||||
|
||||
/**
|
||||
* Whether the preview is updating.
|
||||
*/
|
||||
private updating = false;
|
||||
|
||||
/**
|
||||
* Whether a preview update request is pending.
|
||||
*/
|
||||
private pendingUpdate = false;
|
||||
|
||||
private constructor(private readonly document: vscode.TextDocument) {
|
||||
this.panel = vscode.window.createWebviewPanel('texinfo.preview', '', vscode.ViewColumn.Beside);
|
||||
this.disposables.push(this.panel.onDidDispose(() => this.destroy()));
|
||||
Preview.map.set(this.document, this);
|
||||
this.updateWebview();
|
||||
}
|
||||
|
||||
private get title() {
|
||||
const updating = this.updating ? '(Updating) ' : '';
|
||||
const fileName = path.basename(this.document.fileName);
|
||||
return `${updating}Preview ${fileName}`;
|
||||
}
|
||||
|
||||
private destroy() {
|
||||
this.disposables.forEach((event) => event.dispose());
|
||||
this.panel.dispose();
|
||||
Preview.map.delete(this.document);
|
||||
}
|
||||
|
||||
private async updateWebview() {
|
||||
if (this.updating) {
|
||||
this.pendingUpdate = true;
|
||||
return;
|
||||
}
|
||||
this.updating = true;
|
||||
this.pendingUpdate = false;
|
||||
this.panel.title = this.title;
|
||||
const htmlCode = await Converter.convert(this.document.fileName);
|
||||
if (htmlCode === undefined) {
|
||||
vscode.window.showErrorMessage(`Failed to show preview for file ${this.document.fileName}.`);
|
||||
} else {
|
||||
this.panel.webview.html = htmlCode;
|
||||
}
|
||||
this.updating = false;
|
||||
this.panel.title = this.title;
|
||||
if (this.pendingUpdate) {
|
||||
this.updateWebview();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* utils.ts - Helper functions
|
||||
*
|
||||
* @author CismonX <admin@cismon.net>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as child_process from 'child_process';
|
||||
|
||||
/**
|
||||
* Open a prompt with two buttons, "Confirm" and "Cancel", and wait for user action.
|
||||
*
|
||||
* @param message The message to be displayed on the prompt.
|
||||
* @param confirm Text to be displayed on the "Confirm" button.
|
||||
* @yields Whether the user clicked the "Confirm" button.
|
||||
*/
|
||||
export async function prompt(message: string, confirm: string) {
|
||||
return confirm === await vscode.window.showInformationMessage(message, confirm, 'Cancel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute command and get output.
|
||||
*
|
||||
* @param path Path to the executable file.
|
||||
* @param args Arguments to be passed to the command.
|
||||
* @param maxBuffer Max output buffer size.
|
||||
* @yields The output data, or `undefined` if execution fails.
|
||||
*/
|
||||
export function exec(path: string, args: string[], maxBuffer: number) {
|
||||
return new Promise<string | undefined>((resolve) => {
|
||||
child_process.execFile(path, args, { maxBuffer: maxBuffer }, (error, stdout, stderr) => {
|
||||
if (stderr) {
|
||||
console.log(stderr);
|
||||
}
|
||||
if (error) {
|
||||
console.error(error);
|
||||
resolve(undefined);
|
||||
} else {
|
||||
resolve(stdout);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"noImplicitReturns": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue