Skip to content

Commit

Permalink
Add errors to invalid #include's
Browse files Browse the repository at this point in the history
  • Loading branch information
RedCMD committed Apr 7, 2024
1 parent 58106a8 commit eef237f
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 23 deletions.
118 changes: 112 additions & 6 deletions out/DiagnosticCollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@ const vscode = require("vscode");
const vscodeOniguruma = require("vscode-oniguruma");
const TreeSitter_1 = require("./TreeSitter");
const extension_1 = require("./extension");
let repoQuery;
function initDiagnostics(context) {
// vscode.window.showInformationMessage(JSON.stringify("initDiagnostics"));
const DiagnosticCollection = vscode.languages.createDiagnosticCollection("textmate");
context.subscriptions.push(DiagnosticCollection);
const repoQueryString = `
(repo
; [(patterns) (include)] (repository ; causes extra 70ms lag
(repository
(repo
(key) @nestRepo))
!match !begin)
`;
repoQuery = TreeSitter_1.jsonParserLanguage.query(repoQueryString);
for (const editor of vscode.window.visibleTextEditors) {
// vscode.window.showInformationMessage(JSON.stringify("visible"));
Diagnostics(editor.document, DiagnosticCollection);
Expand All @@ -31,6 +41,9 @@ function Diagnostics(document, Diagnostics) {
if (!vscode.languages.match(extension_1.DocumentSelector, document)) {
return;
}
const trees = (0, TreeSitter_1.getTrees)(document);
const jsonTree = trees.jsonTree;
const rootNode = jsonTree.rootNode;
const diagnostics = [];
if (false) { // TreeSitter JSON errors
// vscode.window.showInformationMessage(JSON.stringify("diagnostics JSON"))
Expand Down Expand Up @@ -151,14 +164,15 @@ function Diagnostics(document, Diagnostics) {
// vscode.window.showInformationMessage(JSON.stringify("diagnostics Regex Oniguruma"));
const trees = (0, TreeSitter_1.getTrees)(document);
// const jsonTree = trees.jsonTree;
const regexTrees = trees.regexTrees;
// const regexTrees = trees.regexTrees;
const regexNodes = trees.regexNodes;
for (const id in regexTrees) {
const regexTree = regexTrees[id];
const node = regexTree.rootNode;
const text = node.text;
const regexNode = regexNodes[node.id];
for (const id in regexNodes) {
const regexNode = regexNodes[id];
const text = regexNode.text;
const key = regexNode.previousNamedSibling;
if (!key) { // `previousNamedSibling` is broken on 0width nodes
continue;
}
let regex = text.replace(/\\[\\\/bfnrt"]|\\u[0-9a-fA-F]{4}/g, regexEscapeReplacer);
if (key.text == 'end' || key.text == 'while') {
// `\\3` could be valid; could be invalid. Who knows?
Expand All @@ -184,6 +198,98 @@ function Diagnostics(document, Diagnostics) {
}
}
}
if (false) { // missing `#includes`
// vscode.window.showInformationMessage(JSON.stringify("diagnostics #includes"))
const includeCaptures = (0, TreeSitter_1.queryNode)(rootNode, `(include (value !scopeName (ruleName) @include))`);
for (const includeCapture of includeCaptures) {
const node = includeCapture.node;
const text = node.text;
const repoQuery = `
(json
(repository
(repo
(key) @rootRepo (.eq? @rootRepo "${text}"))))
(repo
; [(patterns) (include)] (repository ; causes too much lag
(repository
(repo
(key) @nestRepo (.eq? @nestRepo "${text}")))
!match !begin)
`;
// const start = performance.now();
const repoCapture = (0, TreeSitter_1.queryNode)(rootNode, repoQuery, node.startPosition, false); // laggy
// vscode.window.showInformationMessage(JSON.stringify(performance.now() - start) + "ms");
if (repoCapture) {
continue;
}
const range = (0, TreeSitter_1.toRange)(node);
const diagnostic = {
range: range,
message: `\`${text}\` was not found in a repository.`,
severity: vscode.DiagnosticSeverity.Error,
source: 'TextMate',
};
diagnostics.push(diagnostic);
}
}
if (true) { // missing `#includes`
// vscode.window.showInformationMessage(JSON.stringify("diagnostics #includes"))
// const start = performance.now();
const includeCaptures = (0, TreeSitter_1.queryNode)(rootNode, `(include (value !scopeName (ruleName) @include))`);
const rootRepoQuery = `(json (repository (repo (key) @rootRepo)))`;
const rootRepoCaptures = (0, TreeSitter_1.queryNode)(rootNode, rootRepoQuery);
// const repoQueryString = `
// ;(json
// ; (repository
// ; (repo
// ; (key) @rootRepo)))
// (repo
// ; [(patterns) (include)] (repository ; causes extra 70ms lag
// (repository
// (repo
// (key) @nestRepo))
// !match !begin)
// `;
// const language = jsonTree.getLanguage();
// const repoQuery = language.query(repoQueryString);
// const queryCaptures = repoQuery.captures(node, startPoint, endPoint || startPoint);
for (const includeCapture of includeCaptures) {
const node = includeCapture.node;
const text = node.text;
// const repoCapture = queryNode(rootNode, repoQuery, node.startPosition, false);
let match = false;
for (const repoCapture of rootRepoCaptures) {
const repoText = repoCapture.node.text;
if (repoText == text) {
match = true;
break;
}
}
if (match) {
continue;
}
const repoCaptures = repoQuery.captures(rootNode, node.startPosition, node.endPosition);
for (const repoCapture of repoCaptures) {
const repoText = repoCapture.node.text;
if (repoText == text) {
match = true;
break;
}
}
if (match) {
continue;
}
const range = (0, TreeSitter_1.toRange)(node);
const diagnostic = {
range: range,
message: `\`${text}\` was not found in a repository.`,
severity: vscode.DiagnosticSeverity.Error,
source: 'TextMate',
};
diagnostics.push(diagnostic);
}
// vscode.window.showInformationMessage(performance.now() - start + "ms");
}
// vscode.window.showInformationMessage(JSON.stringify(diagnostics));
Diagnostics.set(document.uri, diagnostics);
}
Expand Down
10 changes: 7 additions & 3 deletions out/TreeSitter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initTreeSitter = exports.trueParent = exports.toPoint = exports.toRange = exports.queryForPosition = exports.queryNode = exports.getLastNode = exports.getComment = exports.getRegexNode = exports.getTree = exports.getTrees = void 0;
exports.initTreeSitter = exports.regexParserLanguage = exports.jsonParserLanguage = exports.trueParent = exports.toPoint = exports.toRange = exports.queryForPosition = exports.queryNode = exports.getLastNode = exports.getComment = exports.getRegexNode = exports.getTree = exports.getTrees = void 0;
const vscode = require("vscode");
const Parser = require("web-tree-sitter");
const extension_1 = require("./extension");
Expand Down Expand Up @@ -57,8 +57,8 @@ function getComment(node) {
exports.getComment = getComment;
function getLastNode(rootNode, type) {
const nodes = rootNode.namedChildren;
while (nodes.length) {
const childNode = nodes.pop(); // bottom up
for (let index = nodes.length - 1; index >= 0; index--) { // bottom up
const childNode = nodes[index];
if (childNode.type == type) {
return childNode;
}
Expand All @@ -67,7 +67,9 @@ function getLastNode(rootNode, type) {
exports.getLastNode = getLastNode;
function queryNode(node, queryString, startPoint, endPoint) {
const language = node.tree.getLanguage();
// const start = performance.now();
const query = language.query(queryString);
// vscode.window.showInformationMessage(performance.now() - start + "ms");
const queryCaptures = query.captures(node, startPoint, endPoint || startPoint);
if (queryCaptures.length > 10000) {
vscode.window.showWarningMessage("Unoptimized Query: " + queryCaptures.length + " results returned:\n" + queryString);
Expand Down Expand Up @@ -154,11 +156,13 @@ async function initTreeSitter(context) {
const jsonWasm = jsonWasmUri.scheme === 'file' ? jsonWasmUri.fsPath : jsonWasmUri.toString(true);
const jsonLanguage = await Parser.Language.load(jsonWasm);
jsonParser.setLanguage(jsonLanguage);
exports.jsonParserLanguage = jsonLanguage;
const regexParser = new Parser();
const regexWasmUri = vscode.Uri.joinPath(context.extensionUri, 'out', 'tree-sitter-regextm.wasm');
const regexWasm = regexWasmUri.scheme === 'file' ? regexWasmUri.fsPath : regexWasmUri.toString(true);
const regexLanguage = await Parser.Language.load(regexWasm);
regexParser.setLanguage(regexLanguage);
exports.regexParserLanguage = regexLanguage;
// vscode.window.showInformationMessage(JSON.stringify("Lang"));
// const jsonParser = new Parser();
// const jsonWasm = context.asAbsolutePath('out/tree-sitter-jsontm.wasm');
Expand Down
2 changes: 1 addition & 1 deletion out/web/extension.js

Large diffs are not rendered by default.

142 changes: 132 additions & 10 deletions src/DiagnosticCollection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as vscode from 'vscode';
import * as vscodeOniguruma from "vscode-oniguruma";
import { getTree, getTrees, queryNode, toRange, trueParent } from "./TreeSitter";
import { getTree, getTrees, jsonParserLanguage, queryNode, toRange, trueParent } from "./TreeSitter";
import { DocumentSelector } from './extension';
import { Query } from 'web-tree-sitter';


type IOnigBinding = {
Expand All @@ -25,11 +26,23 @@ type OnigScanner = vscodeOniguruma.OnigScanner & {
readonly _options: vscodeOniguruma.FindOption[];
}

let repoQuery: Query;

export function initDiagnostics(context: vscode.ExtensionContext) {
// vscode.window.showInformationMessage(JSON.stringify("initDiagnostics"));
const DiagnosticCollection = vscode.languages.createDiagnosticCollection("textmate");
context.subscriptions.push(DiagnosticCollection);

const repoQueryString = `
(repo
; [(patterns) (include)] (repository ; causes extra 70ms lag
(repository
(repo
(key) @nestRepo))
!match !begin)
`;
repoQuery = jsonParserLanguage.query(repoQueryString);

for (const editor of vscode.window.visibleTextEditors) {
// vscode.window.showInformationMessage(JSON.stringify("visible"));
Diagnostics(editor.document, DiagnosticCollection);
Expand Down Expand Up @@ -61,6 +74,11 @@ function Diagnostics(document: vscode.TextDocument, Diagnostics: vscode.Diagnost
if (!vscode.languages.match(DocumentSelector, document)) {
return;
}

const trees = getTrees(document);
const jsonTree = trees.jsonTree;
const rootNode = jsonTree.rootNode;

const diagnostics: vscode.Diagnostic[] = [];

if (false) { // TreeSitter JSON errors
Expand Down Expand Up @@ -195,17 +213,16 @@ function Diagnostics(document: vscode.TextDocument, Diagnostics: vscode.Diagnost
// vscode.window.showInformationMessage(JSON.stringify("diagnostics Regex Oniguruma"));
const trees = getTrees(document);
// const jsonTree = trees.jsonTree;
const regexTrees = trees.regexTrees;
// const regexTrees = trees.regexTrees;
const regexNodes = trees.regexNodes;


for (const id in regexTrees) {
const regexTree = regexTrees[id];
const node = regexTree.rootNode;
const text = node.text;

const regexNode = regexNodes[node.id];
for (const id in regexNodes) {
const regexNode = regexNodes[id];
const text = regexNode.text;
const key = regexNode.previousNamedSibling;
if (!key) { // `previousNamedSibling` is broken on 0width nodes
continue;
}

let regex = text.replace(/\\[\\\/bfnrt"]|\\u[0-9a-fA-F]{4}/g, regexEscapeReplacer);
if (key.text == 'end' || key.text == 'while') {
Expand All @@ -223,7 +240,7 @@ function Diagnostics(document: vscode.TextDocument, Diagnostics: vscode.Diagnost

// const string = vscodeOniguruma.createOnigString(''); // blank. Maybe can test against a user provided string?
// const match = scanner.findNextMatchSync(string, 0); // returns null if `regex` is invalid

if (errorCode != 'undefined error code') {
const range = toRange(key);
const diagnostic: vscode.Diagnostic = {
Expand All @@ -237,6 +254,111 @@ function Diagnostics(document: vscode.TextDocument, Diagnostics: vscode.Diagnost
}
}

if (false) { // missing `#includes`
// vscode.window.showInformationMessage(JSON.stringify("diagnostics #includes"))

const includeCaptures = queryNode(rootNode, `(include (value !scopeName (ruleName) @include))`);

for (const includeCapture of includeCaptures) {
const node = includeCapture.node;
const text = node.text;

const repoQuery = `
(json
(repository
(repo
(key) @rootRepo (.eq? @rootRepo "${text}"))))
(repo
; [(patterns) (include)] (repository ; causes too much lag
(repository
(repo
(key) @nestRepo (.eq? @nestRepo "${text}")))
!match !begin)
`;
// const start = performance.now();
const repoCapture = queryNode(rootNode, repoQuery, node.startPosition, false); // laggy
// vscode.window.showInformationMessage(JSON.stringify(performance.now() - start) + "ms");
if (repoCapture) {
continue;
}

const range = toRange(node);
const diagnostic: vscode.Diagnostic = {
range: range,
message: `\`${text}\` was not found in a repository.`,
severity: vscode.DiagnosticSeverity.Error,
source: 'TextMate',
};
diagnostics.push(diagnostic);
}
}

if (true) { // missing `#includes`
// vscode.window.showInformationMessage(JSON.stringify("diagnostics #includes"))
// const start = performance.now();

const includeCaptures = queryNode(rootNode, `(include (value !scopeName (ruleName) @include))`);

const rootRepoQuery = `(json (repository (repo (key) @rootRepo)))`;
const rootRepoCaptures = queryNode(rootNode, rootRepoQuery);

// const repoQueryString = `
// ;(json
// ; (repository
// ; (repo
// ; (key) @rootRepo)))
// (repo
// ; [(patterns) (include)] (repository ; causes extra 70ms lag
// (repository
// (repo
// (key) @nestRepo))
// !match !begin)
// `;
// const language = jsonTree.getLanguage();
// const repoQuery = language.query(repoQueryString);
// const queryCaptures = repoQuery.captures(node, startPoint, endPoint || startPoint);

for (const includeCapture of includeCaptures) {
const node = includeCapture.node;
const text = node.text;

// const repoCapture = queryNode(rootNode, repoQuery, node.startPosition, false);
let match = false;
for (const repoCapture of rootRepoCaptures) {
const repoText = repoCapture.node.text;
if (repoText == text) {
match = true;
break;
}
}
if (match) {
continue;
}

const repoCaptures = repoQuery.captures(rootNode, node.startPosition, node.endPosition);
for (const repoCapture of repoCaptures) {
const repoText = repoCapture.node.text;
if (repoText == text) {
match = true;
break;
}
}
if (match) {
continue;
}

const range = toRange(node);
const diagnostic: vscode.Diagnostic = {
range: range,
message: `\`${text}\` was not found in a repository.`,
severity: vscode.DiagnosticSeverity.Error,
source: 'TextMate',
};
diagnostics.push(diagnostic);
}
// vscode.window.showInformationMessage(performance.now() - start + "ms");
}

// vscode.window.showInformationMessage(JSON.stringify(diagnostics));
Diagnostics.set(document.uri, diagnostics);
}
Expand Down
Loading

0 comments on commit eef237f

Please sign in to comment.