diff --git a/lib/make.js b/lib/make.js index 8344cd7..1005469 100644 --- a/lib/make.js +++ b/lib/make.js @@ -6,6 +6,7 @@ import os from 'os'; import { exec } from 'child_process'; import voucher from 'voucher'; import { EventEmitter } from 'events'; +import XRegExp from 'xregexp'; export const config = { jobs: { @@ -27,18 +28,58 @@ export const config = { }; export function provideBuilder() { - const gccErrorMatch = '(?([A-Za-z]:[\\/])?[^:\\n]+):(?\\d+):(?\\d+):\\s*(fatal error|error):\\s*(?.+)'; - const ocamlErrorMatch = '(?[\\/0-9a-zA-Z\\._\\-]+)", line (?\\d+), characters (?\\d+)-(?\\d+):\\n(?.+)'; - const golangErrorMatch = '(?([A-Za-z]:[\\/])?[^:\\n]+):(?\\d+):\\s*(?.*error.+)'; - const errorMatch = [ - gccErrorMatch, ocamlErrorMatch, golangErrorMatch - ]; + const gccErrorExpr = new XRegExp('(?([A-Za-z]:[\\/])?[^:\\n]+):(?\\d+):(?\\d+):\\s*(fatal error|error):\\s*(?.+)'); + const ocamlErrorExpr = new XRegExp('(?[\\/0-9a-zA-Z\\._\\-]+)", line (?\\d+), characters (?\\d+)-(?\\d+):\\n(?.+)'); + const golangErrorExpr = new XRegExp('(?([A-Za-z]:[\\/])?[^:\\n]+):(?\\d+):\\s*(?.*error.+)'); + const errorExpr = [ gccErrorExpr, ocamlErrorExpr, golangErrorExpr ]; - const gccWarningMatch = '(?([A-Za-z]:[\\/])?[^:\\n]+):(?\\d+):(?\\d+):\\s*(warning):\\s*(?.+)'; - const warningMatch = [ - gccWarningMatch + const gccWarningExpr = new XRegExp('(?([A-Za-z]:[\\/])?[^:\\n]+):(?\\d+):(?\\d+):\\s*(warning):\\s*(?.+)'); + const warningExpr = [ + gccWarningExpr ]; + function eMatch(regexList, dir, matchObjects, string, type) { + regexList.forEach(function (regex) { + XRegExp.forEach(string, regex, function (match) { + // map the regex match to the error object that atom-build expects + matchObjects.push({ + file: dir ? dir + '/' + match.file : match.file, + line: match.line, + col: match.col, + col_end: match.col_end, + type: type, + message: match.message + }); + }); + }); + } + + function functionMatch(o) { + const enterDir = /^make\[\d+\]: Entering directory [`']([^']+)[`']$/; + const matchObjects = []; + let scopeBuffer = ''; + // stores the current directory + let dir = null; + // iterate over the output by lines + o.split(/\r?\n/).forEach(line => { + // update the current directory on lines with `Entering directory` + const dirMatch = enterDir.exec(line); + if (dirMatch) { + // flush buffer + eMatch(errorExpr, dir, matchObjects, scopeBuffer, 'Error'); + eMatch(warningExpr, dir, matchObjects, scopeBuffer, 'Warning'); + scopeBuffer = ''; + // Update dir + dir = dirMatch[1]; + } else { + scopeBuffer += line + '\n'; + } + }); + eMatch(errorExpr, dir, matchObjects, scopeBuffer, 'Error'); + eMatch(warningExpr, dir, matchObjects, scopeBuffer, 'Warning'); + return matchObjects; + } + return class MakeBuildProvider extends EventEmitter { constructor(cwd) { super(); @@ -65,8 +106,7 @@ export function provideBuilder() { name: 'GNU Make: default (no target)', args: args, sh: false, - errorMatch: errorMatch, - warningMatch: warningMatch + functionMatch: functionMatch }; const promise = atom.config.get('build-make.useMake') ? @@ -75,7 +115,7 @@ export function provideBuilder() { return promise.then(output => { return [ defaultTarget ].concat(output.toString('utf8') - .split(/[\r\n]{1,2}/) + .split(/[\r?\n]{1,2}/) .filter(line => /^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/.test(line)) .map(targetLine => targetLine.split(':').shift()) .filter( (elem, pos, array) => (array.indexOf(elem) === pos) ) @@ -84,8 +124,7 @@ export function provideBuilder() { args: args.concat([ target ]), name: `GNU Make: ${target}`, sh: false, - errorMatch: errorMatch, - warningMatch: warningMatch + functionMatch: functionMatch }))); }).catch(e => [ defaultTarget ]); } diff --git a/package.json b/package.json index 07f1e22..e965114 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ ], "main": "lib/make.js", "dependencies": { - "voucher": "^0.1.2" + "voucher": "^0.1.2", + "xregexp": "^3.1.0" } }