|
1 | 1 | 'use babel'; |
2 | 2 |
|
| 3 | +import * as helpers from 'atom-linter'; |
| 4 | +import { extname } from 'path'; |
| 5 | +// eslint-disable-next-line import/extensions, import/no-extraneous-dependencies |
| 6 | +import { CompositeDisposable } from 'atom'; |
| 7 | + |
3 | 8 | export default { |
4 | | - config: { |
5 | | - rubyExecutablePath: { |
6 | | - type: 'string', |
7 | | - default: 'ruby', |
8 | | - }, |
9 | | - ignoredExtensions: { |
10 | | - type: 'array', |
11 | | - default: ['erb', 'md'], |
12 | | - items: { |
13 | | - type: 'string', |
14 | | - }, |
15 | | - }, |
| 9 | + activate() { |
| 10 | + require('atom-package-deps').install('linter-ruby'); |
| 11 | + |
| 12 | + this.subscriptions = new CompositeDisposable(); |
| 13 | + this.subscriptions.add(atom.config.observe('linter-ruby.rubyExecutablePath', |
| 14 | + (value) => { this.executablePath = value; })); |
| 15 | + this.subscriptions.add(atom.config.observe('linter-ruby.ignoredExtensions', |
| 16 | + (value) => { this.ignoredExtensions = value; })); |
16 | 17 | }, |
17 | 18 |
|
18 | | - activate: () => { |
19 | | - // We are now using steelbrain's package dependency package to install our |
20 | | - // dependencies. |
21 | | - require('atom-package-deps').install(); |
| 19 | + deactivate() { |
| 20 | + this.subscriptions.dispose(); |
22 | 21 | }, |
23 | 22 |
|
24 | | - provideLinter: () => { |
25 | | - const helpers = require('atom-linter'); |
26 | | - const Path = require('path'); |
27 | | - const regex = /.+:(\d+):\s*(.+?)[,:]\s(.+)/; |
| 23 | + provideLinter() { |
| 24 | + const regex = /.+:(\d+):\s*(.+?)[,:]\s(.+)/g; |
28 | 25 | return { |
29 | 26 | name: 'Ruby', |
30 | 27 | grammarScopes: ['source.ruby', 'source.ruby.rails', 'source.ruby.rspec'], |
31 | 28 | scope: 'file', |
32 | 29 | lintOnFly: true, |
33 | | - lint: (activeEditor) => { |
34 | | - const command = atom.config.get('linter-ruby.rubyExecutablePath'); |
35 | | - const ignored = atom.config.get('linter-ruby.ignoredExtensions'); |
36 | | - const filePath = activeEditor.getPath(); |
37 | | - const fileExtension = Path.extname(filePath).substr(1); |
| 30 | + lint: async (textEditor) => { |
| 31 | + const filePath = textEditor.getPath(); |
| 32 | + const fileText = textEditor.getText(); |
| 33 | + const fileExtension = extname(filePath).substr(1); |
38 | 34 |
|
39 | | - if (ignored.includes(fileExtension)) { |
| 35 | + if (this.ignoredExtensions.includes(fileExtension)) { |
40 | 36 | return []; |
41 | 37 | } |
42 | 38 |
|
43 | | - return helpers.exec(command, ['-wc', '-E utf-8'], { stdin: activeEditor.getText(), stream: 'stderr' }).then((output) => { |
44 | | - const toReturn = []; |
45 | | - output.split(/\r?\n/).forEach((line) => { |
46 | | - const matches = regex.exec(line); |
47 | | - if (matches === null) { |
48 | | - return; |
49 | | - } |
50 | | - const msgLine = Number.parseInt(matches[1] - 1, 10); |
51 | | - toReturn.push({ |
52 | | - range: helpers.rangeFromLineNumber(activeEditor, msgLine), |
53 | | - type: matches[2], |
54 | | - text: matches[3], |
55 | | - filePath, |
56 | | - }); |
| 39 | + const execArgs = ['-wc', '-Eutf-8']; |
| 40 | + const execOpts = { |
| 41 | + stdin: fileText, |
| 42 | + stream: 'stderr', |
| 43 | + allowEmptyStderr: true, |
| 44 | + }; |
| 45 | + const output = await helpers.exec(this.executablePath, execArgs, execOpts); |
| 46 | + if (textEditor.getText() !== fileText) { |
| 47 | + // File contents have changed, just tell Linter not to update messages |
| 48 | + return null; |
| 49 | + } |
| 50 | + const toReturn = []; |
| 51 | + let match = regex.exec(output); |
| 52 | + while (match !== null) { |
| 53 | + const msgLine = Number.parseInt(match[1] - 1, 10); |
| 54 | + toReturn.push({ |
| 55 | + range: helpers.rangeFromLineNumber(textEditor, msgLine), |
| 56 | + type: match[2], |
| 57 | + text: match[3], |
| 58 | + filePath, |
57 | 59 | }); |
58 | | - return toReturn; |
59 | | - }); |
| 60 | + match = regex.exec(output); |
| 61 | + } |
| 62 | + return toReturn; |
60 | 63 | }, |
61 | 64 | }; |
62 | 65 | }, |
|
0 commit comments