├── .gitignore ├── spec ├── fixtures │ ├── English.md │ └── properEnglish.md └── linter-write-good-spec.js ├── flags.png ├── screenshot.png ├── LICENSE.md ├── .travis.yml ├── package.json ├── README.md ├── CHANGELOG.md └── lib └── init.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /spec/fixtures/English.md: -------------------------------------------------------------------------------- 1 | Remarkably few developers write well. 2 | -------------------------------------------------------------------------------- /spec/fixtures/properEnglish.md: -------------------------------------------------------------------------------- 1 | It's rare for developers to write well. 2 | -------------------------------------------------------------------------------- /flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtomLinter/linter-write-good/HEAD/flags.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AtomLinter/linter-write-good/HEAD/screenshot.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 George Marchin 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | ### Project specific config ### 2 | language: node_js 3 | node_js: lts/* 4 | install: skip 5 | os: linux 6 | 7 | jobs: 8 | include: 9 | # Test Atom versions 10 | - stage: test 11 | env: ATOM_CHANNEL=stable 12 | - stage: test 13 | env: ATOM_CHANNEL=beta 14 | 15 | # Check the commit messages 16 | - stage: test 17 | install: 18 | - npm install 19 | before_script: skip 20 | script: 21 | - commitlint-travis 22 | 23 | - stage: release 24 | # Since the deploy needs APM, currently the simplest method is to run 25 | # build-package.sh, which requires the specs to pass. 26 | before_deploy: 27 | - export PATH=${PATH}:${HOME}/atom/usr/bin/ 28 | deploy: 29 | provider: script 30 | skip_cleanup: true 31 | script: 32 | - npx semantic-release 33 | 34 | ### Generic setup follows ### 35 | script: 36 | - curl -s -O https://raw.githubusercontent.com/atom/ci/master/build-package.sh 37 | - chmod u+x build-package.sh 38 | - "./build-package.sh" 39 | 40 | notifications: 41 | email: 42 | on_success: never 43 | on_failure: change 44 | 45 | branches: 46 | only: 47 | - master 48 | 49 | git: 50 | depth: 10 51 | 52 | dist: trusty 53 | 54 | sudo: false 55 | 56 | addons: 57 | apt: 58 | packages: 59 | - build-essential 60 | - fakeroot 61 | - git 62 | - libsecret-1-dev 63 | 64 | stages: 65 | - test 66 | - name: release 67 | if: (NOT type = pull_request) AND branch = master 68 | -------------------------------------------------------------------------------- /spec/linter-write-good-spec.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | 3 | import * as path from 'path'; 4 | import { 5 | // eslint-disable-next-line no-unused-vars 6 | it, fit, wait, beforeEach, afterEach, 7 | } from 'jasmine-fix'; 8 | 9 | const { lint } = require('../lib/init').provideLinter(); 10 | 11 | const validPath = path.join(__dirname, 'fixtures', 'properEnglish.md'); 12 | const badPath = path.join(__dirname, 'fixtures', 'English.md'); 13 | 14 | describe('The write-good provider for Linter', () => { 15 | beforeEach(async () => { 16 | atom.workspace.destroyActivePaneItem(); 17 | await atom.packages.activatePackage('linter-write-good'); 18 | }); 19 | 20 | it('checks a file with issues', async () => { 21 | const editor = await atom.workspace.open(badPath); 22 | const messages = await lint(editor); 23 | 24 | expect(messages.length).toBe(2); 25 | 26 | expect(messages[0].severity).toBe('error'); 27 | expect(messages[0].excerpt).toBe('"Remarkably" is a weasel word and can weaken meaning'); 28 | expect(messages[0].location.file).toBe(badPath); 29 | expect(messages[0].location.position).toEqual([[0, 0], [0, 10]]); 30 | 31 | expect(messages[1].severity).toBe('error'); 32 | expect(messages[1].excerpt).toBe('"few" is a weasel word'); 33 | expect(messages[1].location.file).toBe(badPath); 34 | expect(messages[1].location.position).toEqual([[0, 11], [0, 14]]); 35 | }); 36 | 37 | it('finds nothing wrong with a valid file', async () => { 38 | const editor = await atom.workspace.open(validPath); 39 | const messages = await lint(editor); 40 | 41 | expect(messages.length).toBe(0); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linter-write-good", 3 | "main": "./lib/init", 4 | "version": "0.9.3", 5 | "private": true, 6 | "description": "Naive linter for English prose for developers who can't write good and wanna learn to do other stuff good too.", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/AtomLinter/linter-write-good.git" 10 | }, 11 | "license": "MIT", 12 | "engines": { 13 | "atom": ">=1.9.0 <2.0.0" 14 | }, 15 | "dependencies": { 16 | "write-good": "1.0.2", 17 | "xregexp": "2.0.0" 18 | }, 19 | "devDependencies": { 20 | "@commitlint/cli": "8.3.5", 21 | "@commitlint/config-conventional": "8.3.4", 22 | "@commitlint/travis-cli": "8.3.5", 23 | "@semantic-release/apm-config": "8.0.0", 24 | "husky": "4.2.3", 25 | "jasmine-fix": "1.3.1", 26 | "semantic-release": "17.0.4" 27 | }, 28 | "providedServices": { 29 | "linter": { 30 | "versions": { 31 | "2.0.0": "provideLinter" 32 | } 33 | } 34 | }, 35 | "release": { 36 | "extends": "@semantic-release/apm-config" 37 | }, 38 | "commitlint": { 39 | "extends": [ 40 | "@commitlint/config-conventional" 41 | ] 42 | }, 43 | "husky": { 44 | "hooks": { 45 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 46 | } 47 | }, 48 | "renovate": { 49 | "extends": [ 50 | "config:base" 51 | ], 52 | "semanticCommits": true, 53 | "rangeStrategy": "pin", 54 | "packageRules": [ 55 | { 56 | "packagePatterns": [ 57 | "^eslint" 58 | ], 59 | "groupName": "ESLint packages" 60 | } 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # linter-write-good 2 | 3 | Naive linter for English prose for developers who can't write good and wanna 4 | learn to do other stuff good too. 5 | 6 | A Linter interface for the [write-good](https://github.com/btford/write-good) 7 | library. 8 | 9 | This provides a variety of english usage text tips when writing documentation 10 | and commit messages. 11 | 12 | This package requires [Linter](https://github.com/AtomLinter/Linter). 13 | 14 | [See it on atom.io](https://atom.io/packages/linter-write-good) 15 | 16 | [See it on github.com](https://github.com/gepoch/linter-write-good) 17 | 18 | ![](https://raw.github.com/gepoch/linter-write-good/master/screenshot.png) 19 | 20 | ## Configuration 21 | 22 | In the package settings, you can use a custom node binary, a custom write-good 23 | script, and pass arguments to the write good command. See 24 | [write-good](https://github.com/btford/write-good) for possible arguments to the 25 | command. 26 | 27 | Moreover, you can set the **severity level** of this linter. The default level 28 | is **Error**. Setting the severity level to **Warning** or **Info** helps 29 | distinguish *write-good* highlighting from the highlighting of an ordinary spell 30 | checker, or higher priority linters. 31 | 32 | ### Note: Additional Linting 33 | 34 | #### E-Prime 35 | 36 | The Write-Good library implements a linter for 37 | [E-Prime](https://github.com/btford/write-good/issues/70) which is off by 38 | default. To enable E-Prime linting, you'll need to add the `--yes-eprime` flag 39 | to the extra arguments input under this package's settings page. 40 | 41 | ![](https://raw.github.com/gepoch/linter-write-good/master/flags.png) 42 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.9.3](https://github.com/AtomLinter/linter-write-good/compare/v0.9.2...v0.9.3) (2019-09-17) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **deps:** update dependency write-good to v1.0.2 ([fd85bab](https://github.com/AtomLinter/linter-write-good/commit/fd85bab)) 7 | 8 | ## [0.9.2](https://github.com/AtomLinter/linter-write-good/compare/v0.9.1...v0.9.2) (2019-04-24) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * **deps:** update dependency write-good to v1 ([6a92b26](https://github.com/AtomLinter/linter-write-good/commit/6a92b26)) 14 | 15 | ## [0.9.1](https://github.com/AtomLinter/linter-write-good/compare/v0.9.0...v0.9.1) (2019-04-24) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * **deps:** add package-lock.json ([155bce3](https://github.com/AtomLinter/linter-write-good/commit/155bce3)) 21 | * **deps:** pin dependencies ([46a5ac6](https://github.com/AtomLinter/linter-write-good/commit/46a5ac6)) 22 | * **deps:** update dependency write-good to v0.13.1 ([a74edc1](https://github.com/AtomLinter/linter-write-good/commit/a74edc1)) 23 | 24 | ## 0.9.0 - Upgrade write-good to optionally support E-Prime linting 25 | * Thanks to @Vorror for creating the origin E-Prime write-good module 26 | 27 | ## 0.8.0 - Added configurable linter level in settings. 28 | * Thanks to @TimKam 29 | 30 | ## 0.7.0 - Added Asciidoc support. 31 | * Resolves [#17](https://github.com/gepoch/linter-write-good/issues/17) 32 | 33 | ## 0.6.1 - Bugfix. 34 | * Fixed [#11](https://github.com/gepoch/linter-write-good/issues/11) 35 | 36 | ## 0.6.0 - Updated to the use the new Linter API. 37 | 38 | ## 0.5.0 - Pass arguments to the underlying write-good library. 39 | * Thanks to @dragonrider23 40 | 41 | ## 0.4.3 - Fixed deprecation warnings. 42 | * Thanks to @k2b6s9j 43 | 44 | ## 0.4.2 - Updated the short description and README. 45 | * Made it more descriptive for potential users. 46 | 47 | ## 0.4.1 - Improved TeX support 48 | * Now activates on all known tex types with language-latex. 49 | 50 | ## 0.4.0 - Added LaTeX support 51 | * Now activates on "text.bibtex" grammar. Requires the [language-latex](https://atom.io/packages/language-latex) plugin. 52 | 53 | ## 0.3.0 - Accept other RST grammar name 54 | * gfm.text was renamed to gfm.restructuredtext. LWG now supports this. 55 | 56 | ## 0.2.0 - Proper Column-Wise highlighting. 57 | * Specific column ranges are now highlighted, instead of nearby words. 58 | 59 | ## 0.1.0 - First Release 60 | * Simple write-good binding. 61 | -------------------------------------------------------------------------------- /lib/init.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | {XRegExp} = require 'xregexp' 3 | {BufferedProcess, CompositeDisposable} = require 'atom' 4 | 5 | writeGoodRe = '[^^]*(?\\^+)[^^]*\n(?.+?) on line (?\\d+) at column (?\\d+)\n?' 6 | 7 | module.exports = 8 | config: 9 | writeGoodPath: 10 | type: 'string' 11 | title: 'Path to the write-good executable. Defaults to a built-in write-good.' 12 | default: path.join __dirname, '..', 'node_modules', 'write-good', 'bin', 'write-good.js' 13 | additionalArgs: 14 | type: 'string' 15 | title: 'Additional arguments to pass to write-good.' 16 | default: '' 17 | nodePath: 18 | type: 'string' 19 | title: 'Path to the node interpreter to use. Defaults to Atom\'s.' 20 | default: path.join atom.packages.getApmPath(), '..', 'node' 21 | severityLevel: 22 | type: 'string' 23 | title: 'Severity level' 24 | default: 'error' 25 | enum: ['error', 'warning', 'info'] 26 | 27 | activate: -> 28 | @subscriptions = new CompositeDisposable 29 | 30 | @subscriptions.add atom.config.observe 'linter-write-good.writeGoodPath', 31 | (writeGoodPath) => 32 | @writeGoodPath = writeGoodPath 33 | 34 | @subscriptions.add atom.config.observe 'linter-write-good.nodePath', 35 | (nodePath) => 36 | @nodePath = nodePath 37 | 38 | @subscriptions.add atom.config.observe 'linter-write-good.additionalArgs', 39 | (additionalArgs) => 40 | @additionalArgs = if additionalArgs 41 | additionalArgs.split ' ' 42 | else 43 | [] 44 | 45 | deactivate: -> 46 | @subscriptions.dispose() 47 | 48 | provideLinter: -> 49 | provider = 50 | name: 'write-good', 51 | 52 | grammarScopes: [ 53 | "source.gfm" 54 | "gfm.restructuredtext" 55 | "source.asciidoc" 56 | "text.md" 57 | "text.git-commit" 58 | "text.plain" 59 | "text.plain.null-grammar" 60 | "text.restructuredtext" 61 | "text.bibtex" 62 | "text.tex.latex" 63 | "text.tex.latex.beamer" 64 | "text.log.latex" 65 | "text.tex.latex.memoir" 66 | "text.tex" 67 | ] 68 | 69 | scope: 'file' # or 'project' 70 | 71 | lintsOnChange: true # must be false for scope: 'project' 72 | 73 | lint: (textEditor) => 74 | return new Promise (resolve, reject) => 75 | filePath = textEditor.getPath() 76 | 77 | output = "" 78 | 79 | process = new BufferedProcess 80 | command: @nodePath 81 | 82 | args: [@writeGoodPath, filePath, @additionalArgs...] 83 | 84 | stdout: (data) -> 85 | output += data 86 | 87 | exit: (code) -> 88 | messages = [] 89 | regex = XRegExp writeGoodRe, @regexFlags 90 | 91 | XRegExp.forEach output, regex, (match, i) -> 92 | match.colStart = parseInt(match.col) 93 | match.lineStart = parseInt(match.line) - 1 94 | match.colEnd = match.colStart + match.offset.length 95 | messages.push 96 | severity: atom.config.get 'linter-write-good.severityLevel' 97 | excerpt: match.message 98 | location: 99 | file: filePath 100 | position: [ 101 | [match.lineStart, match.colStart] 102 | [match.lineStart, match.colEnd] 103 | ] 104 | 105 | resolve messages 106 | 107 | process.onWillThrowError ({error,handle}) -> 108 | atom.notifications.addError "Failed to run #{@nodePath} #{@writeGoodPath}", 109 | detail: "#{error.message}" 110 | dismissable: true 111 | handle() 112 | resolve [] 113 | --------------------------------------------------------------------------------