|
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