diff --git a/src/dfmt-check.ts b/src/dfmt-check.ts new file mode 100644 index 0000000..05fe6e7 --- /dev/null +++ b/src/dfmt-check.ts @@ -0,0 +1,40 @@ +import * as vscode from "vscode" + +function getMatchIndices(regex: RegExp, str: string) { + let result: number[] = []; + let match: RegExpExecArray; + while (match = regex.exec(str)) + result.push(match.index); + return result; +} + +let validDfmt = /\/\/dfmt (off|on)(\n|\s+|$)/; + +export function lintDfmt(doc: vscode.TextDocument, code: string) { + let locations = getMatchIndices(/\/\/dfmt/g, code); + let issues: vscode.Diagnostic[] = []; + let isOn: boolean = true; + locations.forEach(location => { + let part = code.substr(location, 11); + let match = validDfmt.exec(part); + if (!match) { + let pos = doc ? doc.positionAt(location) : new vscode.Position(0, 0); + issues.push(new vscode.Diagnostic(new vscode.Range(pos, pos.translate(0, 100)), "Not a valid dfmt command (try //dfmt off or //dfmt on instead)", vscode.DiagnosticSeverity.Warning)); + } else { + if (match[1] == "off") { + if (!isOn) { + let pos = doc ? doc.positionAt(location) : new vscode.Position(0, 0); + issues.push(new vscode.Diagnostic(new vscode.Range(pos, pos.translate(0, 10)), "Redundant //dfmt off", vscode.DiagnosticSeverity.Information)); + } + isOn = false; + } else { + if (isOn) { + let pos = doc ? doc.positionAt(location) : new vscode.Position(0, 0); + issues.push(new vscode.Diagnostic(new vscode.Range(pos, pos.translate(0, 9)), "Redundant //dfmt on", vscode.DiagnosticSeverity.Information)); + } + isOn = true; + } + } + }); + return issues; +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 4b99225..d258c44 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,6 +6,7 @@ import { uploadCode } from "./util" import * as statusbar from "./statusbar" import * as path from "path" import { DlangUIHandler } from "./dlangui" +import { lintDfmt } from "./dfmt-check" let diagnosticCollection: vscode.DiagnosticCollection; @@ -21,7 +22,7 @@ export function activate(context: vscode.ExtensionContext) { let workspaced = new WorkspaceD(vscode.workspace.rootPath); context.subscriptions.push(vscode.languages.registerCompletionItemProvider(DML_MODE, workspaced.getDlangUI())); - + context.subscriptions.push(vscode.languages.registerCompletionItemProvider(D_MODE, workspaced, ".")); context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(D_MODE, workspaced, "(", ",")); context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(D_MODE, workspaced)); @@ -79,7 +80,7 @@ export function activate(context: vscode.ExtensionContext) { decreaseIndentPattern: /\}/, increaseIndentPattern: /\{/ }, - + wordPattern: /[a-zA-Z_][a-zA-Z0-9_]*/g, brackets: [ @@ -95,7 +96,34 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(diagnosticCollection); let version; - let oldLint = [[], []]; + let writeTimeout; + let oldLint: [vscode.Uri, vscode.Diagnostic[]][][] = [[], [], []]; + context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => { + clearTimeout(writeTimeout); + writeTimeout = setTimeout(function() { + let document = event.document; + if (document.languageId != "d") + return; + version = document.version; + let target = version; + if (config().get("enableLinting", true)) { + let allErrors: [vscode.Uri, vscode.Diagnostic[]][] = []; + + let fresh = true; + let buildErrors = () => { + allErrors = []; + oldLint.forEach(errors => { + allErrors.push.apply(allErrors, errors); + }); + diagnosticCollection.set(allErrors); + }; + + oldLint[2] = [[document.uri, lintDfmt(document, document.getText())]]; + buildErrors(); + } + }, 500); + })); + context.subscriptions.push(vscode.workspace.onDidSaveTextDocument(document => { if (document.languageId != "d") return; @@ -113,6 +141,8 @@ export function activate(context: vscode.ExtensionContext) { diagnosticCollection.set(allErrors); }; + oldLint[2] = [[document.uri, lintDfmt(document, document.getText())]]; + buildErrors(); workspaced.lint(document).then((errors: [vscode.Uri, vscode.Diagnostic[]][]) => { if (target == version) { oldLint[0] = errors; @@ -196,7 +226,7 @@ export function activate(context: vscode.ExtensionContext) { vscode.window.showErrorMessage("Could not update imports. dub might not be initialized yet!"); }); })); - + context.subscriptions.push(vscode.commands.registerCommand("code-d.insertDscanner", () => { vscode.window.activeTextEditor.edit((bld) => { bld.insert(vscode.window.activeTextEditor.selection.start, `; Configurue which static analysis checks are enabled diff --git a/test/dfmt-check.test.ts b/test/dfmt-check.test.ts new file mode 100644 index 0000000..7559359 --- /dev/null +++ b/test/dfmt-check.test.ts @@ -0,0 +1,30 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { lintDfmt } from '../src/dfmt-check'; + +// Defines a Mocha test suite to group tests of similar kind together +suite("dfmt lint", () => { + test("misspelling on/off", () => { + let linted = lintDfmt(undefined, `void foo() { + //dfmt offs + int i = 5; + //dfmt onf + }`); + assert.strictEqual(linted.length, 2); + assert.strictEqual(linted[0].severity, vscode.DiagnosticSeverity.Warning); + assert.strictEqual(linted[1].severity, vscode.DiagnosticSeverity.Warning); + }); + test("redundant on/off", () => { + let linted = lintDfmt(undefined, `void foo() { + //dfmt on + //dfmt off + int i = 5; + //dfmt off + //dfmt ons + }`); + assert.strictEqual(linted.length, 3); + assert.strictEqual(linted[0].severity, vscode.DiagnosticSeverity.Information); + assert.strictEqual(linted[1].severity, vscode.DiagnosticSeverity.Information); + assert.strictEqual(linted[2].severity, vscode.DiagnosticSeverity.Warning); + }); +}); \ No newline at end of file diff --git a/test/extension.test.ts b/test/extension.test.ts deleted file mode 100644 index 1cec6f4..0000000 --- a/test/extension.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -// -// Note: This example test is leveraging the Mocha test framework. -// Please refer to their documentation on https://mochajs.org/ for help. -// - -// The module 'assert' provides assertion methods from node -import * as assert from 'assert'; - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -import * as vscode from 'vscode'; -import * as myExtension from '../src/extension'; - -// Defines a Mocha test suite to group tests of similar kind together -suite("Extension Tests", () => { - - // Defines a Mocha unit test - test("Something 1", () => { - assert.equal(-1, [1, 2, 3].indexOf(5)); - assert.equal(-1, [1, 2, 3].indexOf(0)); - }); -}); \ No newline at end of file