Add vscode extension, command line argument, and positioned error handling.

This commit is contained in:
2024-07-04 23:40:38 -04:00
parent 0cad438f4d
commit b9f921ab3b
24 changed files with 5701 additions and 98 deletions

View File

@@ -0,0 +1,30 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/naming-convention": [
"warn",
{
"selector": "import",
"format": [ "camelCase", "PascalCase" ]
}
],
"@typescript-eslint/semi": "warn",
"curly": "warn",
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off"
},
"ignorePatterns": [
"out",
"dist",
"**/*.d.ts"
]
}

4
newt-vscode/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
dist
node_modules
*.vsix

View File

@@ -0,0 +1,4 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md

9
newt-vscode/CHANGELOG.md Normal file
View File

@@ -0,0 +1,9 @@
# Change Log
All notable changes to the "newt-vscode" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

3
newt-vscode/README.md Normal file
View File

@@ -0,0 +1,3 @@
# newt-vscode README
newt extension for vscode

56
newt-vscode/esbuild.js Normal file
View File

@@ -0,0 +1,56 @@
const esbuild = require("esbuild");
const production = process.argv.includes('--production');
const watch = process.argv.includes('--watch');
/**
* @type {import('esbuild').Plugin}
*/
const esbuildProblemMatcherPlugin = {
name: 'esbuild-problem-matcher',
setup(build) {
build.onStart(() => {
console.log('[watch] build started');
});
build.onEnd((result) => {
result.errors.forEach(({ text, location }) => {
console.error(`✘ [ERROR] ${text}`);
console.error(` ${location.file}:${location.line}:${location.column}:`);
});
console.log('[watch] build finished');
});
},
};
async function main() {
const ctx = await esbuild.context({
entryPoints: [
'src/extension.ts'
],
bundle: true,
format: 'cjs',
minify: production,
sourcemap: !production,
sourcesContent: false,
platform: 'node',
outfile: 'dist/extension.js',
external: ['vscode'],
logLevel: 'silent',
plugins: [
/* add to the end of plugins array */
esbuildProblemMatcherPlugin,
],
});
if (watch) {
await ctx.watch();
} else {
await ctx.rebuild();
await ctx.dispose();
}
}
main().catch(e => {
console.error(e);
process.exit(1);
});

View File

@@ -0,0 +1,30 @@
{
"comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "--",
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
"blockComment": [ "/-", "-/" ]
},
// symbols used as brackets
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
// symbols that are auto closed when typing
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
],
// symbols that can be used to surround a selection
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"],
["\"", "\""],
["'", "'"]
]
}

5140
newt-vscode/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

62
newt-vscode/package.json Normal file
View File

@@ -0,0 +1,62 @@
{
"name": "newt-vscode",
"displayName": "newt-vscode",
"description": "newt language support",
"version": "0.0.1",
"license": "MIT",
"engines": {
"vscode": "^1.91.0"
},
"categories": [
"Programming Languages"
],
"activationEvents": [
],
"main": "./dist/extension.js",
"contributes": {
"languages": [{
"id": "newt",
"aliases": ["newt", "newt"],
"extensions": ["newt"],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "newt",
"scopeName": "source.newt",
"path": "./syntaxes/newt.tmLanguage.json"
}],
"commands": [
{
"command": "newt-vscode.check",
"title": "Check newt file"
}
]
},
"scripts": {
"vscode:prepublish": "npm run package",
"compile": "npm run check-types && npm run lint && node esbuild.js",
"watch": "npm-run-all -p watch:*",
"watch:esbuild": "node esbuild.js --watch",
"package": "npm run check-types && npm run lint && node esbuild.js --production",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "npm run compile-tests && npm run compile && npm run lint",
"check-types": "tsc --noEmit",
"lint": "eslint src --ext ts",
"test": "vscode-test"
},
"devDependencies": {
"@types/mocha": "^10.0.7",
"@types/node": "20.x",
"@types/vscode": "^1.90.0",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.11.0",
"@vscode/test-cli": "^0.0.9",
"@vscode/test-electron": "^2.4.0",
"esbuild": "^0.21.5",
"eslint": "^8.57.0",
"npm-run-all": "^4.1.5",
"typescript": "^5.4.5"
}
}

View File

@@ -0,0 +1,91 @@
import * as vscode from "vscode";
import { exec } from "child_process";
import path from "path";
export function activate(context: vscode.ExtensionContext) {
const diagnosticCollection =
vscode.languages.createDiagnosticCollection("newt");
function checkDocument(document: vscode.TextDocument) {
const fileName = document.fileName;
// Is there a better way to do this? It will get fussy with quoting and all plus it's not visible to the user.
const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri);
const cwd = workspaceFolder
? workspaceFolder.uri.fsPath
: path.dirname(fileName);
const config = vscode.workspace.getConfiguration("newt");
const cmd = config.get<string>("path", "build/exec/newt");
const command = `${cmd} ${fileName}`;
exec(command, { cwd }, (err, stdout, _stderr) => {
if (err && err.code !== 1) {
vscode.window.showErrorMessage(`newt error: ${err}`);
}
// extract errors and messages from stdout
const lines = stdout.split("\n");
const diagnostics: vscode.Diagnostic[] = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const match = line.match(/ERROR at \((\d+), (\d+)\): (.*)/);
if (match) {
let [_full, line, column, message] = match;
let lnum = Number(line);
let cnum = Number(column);
let start = new vscode.Position(lnum, cnum);
// we don't have the full range, so grab the surrounding word
let end = new vscode.Position(lnum, cnum+1);
let range =
document.getWordRangeAtPosition(start) ??
new vscode.Range(start, end);
// heuristics to grab the entire message:
// anything indented
// Context:, or Goal: are part of PRINTME
// unexpected / expecting appear in parse errors
while (
lines[i + 1]?.match(/^( )/)
) {
message += "\n" + lines[++i];
}
const severity = vscode.DiagnosticSeverity.Error;
const diag = new vscode.Diagnostic(range, message, severity);
diagnostics.push(diag);
}
}
diagnosticCollection.set(vscode.Uri.file(fileName), diagnostics);
});
}
const runPiForall = vscode.commands.registerCommand(
"newt-vscode.check",
() => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor.document;
if (document.fileName.endsWith(".newt")) {
checkDocument(document);
}
}
}
);
context.subscriptions.push(runPiForall);
vscode.workspace.onDidSaveTextDocument((document) => {
if (document.fileName.endsWith(".newt")) {
vscode.commands.executeCommand("newt-vscode.check");
}
});
vscode.workspace.onDidOpenTextDocument((document) => {
if (document.fileName.endsWith(".newt")) {
vscode.commands.executeCommand("newt-vscode.check");
}
});
for (let document of vscode.workspace.textDocuments) {
if (document.fileName.endsWith(".newt")) {
checkDocument(document);
}
}
context.subscriptions.push(diagnosticCollection);
}
export function deactivate() {}

View File

@@ -0,0 +1,48 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "newt",
"scopeName": "source.newt",
"patterns": [
{
"name": "comment.block.newt",
"begin": "/-",
"end": "`-/",
"contentName": "comment.block.newt"
},
{
"name": "comment.line.newt",
"begin": "--",
"end": "\\n"
},
{
"name": "variable.other.constant",
"match": "([\\w]+)\\."
},
{
"name": "entity.name.variable",
"match": "\\.([\\w]+)"
},
{
"name": "punctuation",
"match": ":|=>|\\"
},
{
"name": "keyword.other.operator.newt",
"match": "[\\p{Math}:!#$%&*+.,/<=>?@\\^|-]+"
},
{
"name": "keyword.command.newt",
"match": "\\b(module)\\b"
},
{
"name": "keyword.newt",
"match": "\\b(data)\\b"
},
// {
// "name": "variable.other.constant.newt",
// "match": "\\b(Type|Id|refl|sym|Gel|ungel)\\b",
// "comment": "These are in the emacs mode, but some are user defined"
// }
]
}

16
newt-vscode/tsconfig.json Normal file
View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"strict": true /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
}
}