Skip to content

Commit 0adc49c

Browse files
* Adding only-lint-on-save configuration.
* Seemed to have messed up configuration last release; fixing. I was following instructions in the console, so not sure how I ended up down the wrong path. * Refactored some of the code to help support the future path of having partial linting. * Added some tests after the refactor. I could still use more tests around release documents, but I don't know how to drive those from tesets currently.
1 parent 5490865 commit 0adc49c

7 files changed

Lines changed: 129 additions & 44 deletions

File tree

.vscodeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ src/**
77
.gitignore
88
tsconfig.json
99
vsc-extension-quickstart.md
10+
write-good-linter-*.vsix

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Press F1 or CTRL+P (or CMD+P) and type out `> ext install travisthetechie.write-
1212

1313
`write-good.write-good-config` is a direct pass through to the underlying [write-good](https://github.com/btford/write-good) engine. To enable eprime check and disable check for so at the start of sentance, add `"write-good.write-good-config": { "eprime": true, "so": false }` to your settings.
1414

15+
`write-good.only-lint-on-save` disables linting during editing for large files. A save triggers linting.
16+
1517
## License and acknowledgements
1618

1719
This is licensed under the MIT open source license. Do what you want with this software, just include notice that it orginated with me.

package.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "write-good-linter",
33
"displayName": "Write Good Linter",
44
"description": "Applies the Write Good Linter to your Markdown, so you can write more good.",
5-
"version": "0.1.3",
5+
"version": "0.1.4",
66
"publisher": "travisthetechie",
77
"engines": {
88
"vscode": "^1.26.0"
@@ -19,6 +19,15 @@
1919
"type": "object",
2020
"title": "write-good",
2121
"properties": {
22+
"write-good.only-lint-on-save": {
23+
"type": [
24+
"null",
25+
"boolean"
26+
],
27+
"default": false,
28+
"markdownDescription": "Disables linting during editing for large files. A save triggers linting.",
29+
"scope": "resource"
30+
},
2231
"write-good.write-good-config": {
2332
"type": [
2433
"object",
@@ -48,7 +57,7 @@
4857
},
4958
"scripts": {
5059
"vscode:prepublish": "tsc -p ./",
51-
"compile": "tsc -watch -p ./",
60+
"compile": "tsc -p ./",
5261
"postinstall": "node ./node_modules/vscode/bin/install"
5362
},
5463
"devDependencies": {

src/extension.ts

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use strict';
22

33
import { workspace, ExtensionContext, TextDocument, languages, Uri,
4-
Diagnostic, DiagnosticSeverity, Range, Position, DiagnosticCollection } from 'vscode';
5-
import * as WriteGood from 'write-good';
4+
Diagnostic, DiagnosticCollection, TextDocumentContentChangeEvent } from 'vscode';
65
import { isNullOrUndefined } from 'util';
6+
import { lintText } from './linter';
77

88
let diagnosticCollection: DiagnosticCollection;
99
let diagnosticMap: Map<string, Diagnostic[]>;
@@ -14,23 +14,40 @@ export function activate(context: ExtensionContext) {
1414
diagnosticCollection = languages.createDiagnosticCollection("Write-Good Lints");
1515
diagnosticMap = new Map();
1616

17-
function isWriteGoodLanguage(languageId) {
17+
if (context == null) return;
18+
19+
function isWriteGoodLanguage(languageId: string) {
1820
let wgLanguages: string = workspace.getConfiguration('write-good').get('languages');
1921
return (wgLanguages.indexOf(languageId) > -1 || wgLanguages === '*');
2022
}
2123

24+
// full lint when document is saved
25+
context.subscriptions.push(workspace.onDidSaveTextDocument(document => {
26+
if (isWriteGoodLanguage(document.languageId)) {
27+
doLint(document);
28+
}
29+
}));
30+
31+
// attempt to only lint changes on motification
2232
context.subscriptions.push(workspace.onDidChangeTextDocument(event => {
2333
if (isWriteGoodLanguage(event.document.languageId)) {
24-
doLint(event.document);
34+
// this doesn't work yet, instead, check for a setting?
35+
// doPartialLint(event.document, event.contentChanges);
36+
const onlyLintOnSave: Boolean = workspace.getConfiguration('write-good').get('only-lint-on-save');
37+
if (!onlyLintOnSave) {
38+
doLint(event.document);
39+
}
2540
}
2641
}));
2742

43+
// full lint on a new document/opened document
2844
context.subscriptions.push(workspace.onDidOpenTextDocument(event => {
2945
if (isWriteGoodLanguage(event.languageId)) {
3046
doLint(event);
3147
}
3248
}));
3349

50+
// clean up any lints when the document is closed
3451
context.subscriptions.push(workspace.onDidCloseTextDocument(event => {
3552
if (diagnosticMap.has(event.uri.toString())) {
3653
diagnosticMap.delete(event.uri.toString());
@@ -43,12 +60,6 @@ export function deactivate() {
4360
console.log("Write-Good Linter deactivating...")
4461
}
4562

46-
interface Suggestion {
47-
index: number,
48-
offset: number,
49-
reason: string
50-
}
51-
5263
function resetDiagnostics() {
5364
diagnosticCollection.clear();
5465

@@ -57,21 +68,41 @@ function resetDiagnostics() {
5768
});
5869
}
5970

60-
function doLint(document: TextDocument) {
61-
var wgConfig: object = workspace.getConfiguration('write-good').get('write-good.write-good-config');
71+
function getWriteGoodConfig() : object {
72+
var wgConfig: object = workspace.getConfiguration('write-good').get('write-good-config');
6273
if (isNullOrUndefined(wgConfig)) {
6374
wgConfig = {};
6475
}
65-
let diagnostics: Diagnostic[] = [];
66-
let lines = document.getText().split(/\r?\n/g);
67-
lines.forEach((line, lineCount) => {
68-
let suggestions : Suggestion[] = WriteGood(line, wgConfig);
69-
suggestions.forEach((suggestion, si) => {
70-
let start = new Position(lineCount, suggestion.index);
71-
let end = new Position(lineCount, suggestion.index + suggestion.offset);
72-
diagnostics.push(new Diagnostic(new Range(start, end), suggestion.reason, DiagnosticSeverity.Warning));
76+
return wgConfig;
77+
}
78+
79+
function doPartialLint(document: TextDocument, changes: TextDocumentContentChangeEvent[]) {
80+
const wgConfig = getWriteGoodConfig();
81+
let diagnostics: Diagnostic[] = diagnosticMap.get(document.uri.toString());
82+
changes.forEach((changeEvent, index) => {
83+
// remove any overlapping diagnostics
84+
let toRemove: number[] = [];
85+
diagnostics.forEach((diagnostic, index) => {
86+
// if the diagnostic range intersects with the change event, we assume the diagnostic should be removed
87+
// and will be re-added with the change event.
88+
if (diagnostic.range.intersection(changeEvent.range) != undefined) {
89+
toRemove.push(index);
90+
}
7391
});
92+
toRemove.forEach((i) => diagnostics.splice(i, 1));
93+
94+
// skip linting if there's content
95+
if(changeEvent.text.length > 0) {
96+
const lineOffset = changeEvent.range.start.line;
97+
lintText(changeEvent.text, wgConfig, lineOffset, diagnostics);
98+
}
7499
});
100+
}
101+
102+
function doLint(document: TextDocument) {
103+
const wgConfig = getWriteGoodConfig();
104+
let diagnostics: Diagnostic[] = [];
105+
lintText(document.getText(), wgConfig, 0, diagnostics);
75106

76107
diagnosticMap.set(document.uri.toString(), diagnostics);
77108
resetDiagnostics();

src/linter.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Diagnostic, DiagnosticSeverity, Range, Position } from 'vscode';
2+
import * as WriteGood from 'write-good';
3+
4+
interface Suggestion {
5+
index: number,
6+
offset: number,
7+
reason: string
8+
}
9+
10+
export function lintText(content: string, wgConfig: object, startingLine: number = 0, diagnostics: Diagnostic[] = []) {
11+
if (content == null) return;
12+
let lines = content.split(/\r?\n/g);
13+
lines.forEach((line, lineCount) => {
14+
let suggestions : Suggestion[] = WriteGood(line, wgConfig);
15+
suggestions.forEach((suggestion, si) => {
16+
let start = new Position(lineCount + startingLine, suggestion.index);
17+
let end = new Position(lineCount + startingLine, suggestion.index + suggestion.offset);
18+
diagnostics.push(new Diagnostic(new Range(start, end), suggestion.reason, DiagnosticSeverity.Warning));
19+
});
20+
});
21+
}

test/extension.test.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

test/linter.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// Note: This example test is leveraging the Mocha test framework.
3+
// Please refer to their documentation on https://mochajs.org/ for help.
4+
//
5+
6+
// The module 'assert' provides assertion methods from node
7+
import * as assert from 'assert';
8+
9+
// You can import and use all API from the 'vscode' module
10+
// as well as import your extension to test it
11+
import { Diagnostic } from 'vscode';
12+
import * as linter from '../src/linter';
13+
14+
suite("Linter Tests", () => {
15+
16+
let wgConfig = {};
17+
let diagonstics: Diagnostic[] = [];
18+
19+
test("Linter accepts empty text", () => {
20+
diagonstics = [];
21+
linter.lintText("", wgConfig, 0, diagonstics);
22+
23+
assert.strictEqual(diagonstics.length, 0);
24+
});
25+
26+
test("Linter accepts null text", () => {
27+
diagonstics = [];
28+
linter.lintText(null, wgConfig, 0, diagonstics);
29+
30+
assert.strictEqual(diagonstics.length, 0);
31+
});
32+
33+
test("Expect diagonstics from input text", () => {
34+
const text = "This is licensed under the MIT open source license.";
35+
diagonstics = [];
36+
linter.lintText(text, wgConfig, 0, diagonstics);
37+
38+
// find 'is licensed'
39+
assert.strictEqual(diagonstics.length, 1);
40+
assert.strictEqual(diagonstics[0].range.start.character, 5);
41+
assert.strictEqual(diagonstics[0].range.end.character, 16);
42+
});
43+
});

0 commit comments

Comments
 (0)