'use babel'

import {BufferedProcess, BufferedNodeProcess} from 'atom'
import Path from 'path'
import FS from 'fs'
import TMP from 'tmp'

let XRegExp = null
const XCache = new Map()
const EventsCache = new WeakMap()

// TODO: Remove this when electron upgrades node
const assign = Object.assign || function(target, source) {
    for (const key in source) {
      target[key] = source[key]
    }
    return target
  }

function _exec(command, args, opts, isNode) {
  const options = assign({
    stream: 'stdout',
    throwOnStdErr: true
  }, opts)

  if (isNode) {
    const env = assign({}, process.env)
    delete env.OS
    assign(options, {env})
  }

  return new Promise(function(resolve, reject) {
    const data = {stdout: [], stderr: []}
    const parameters = {
      command,
      args,
      options,
      stdout: function(chunk) {
        data.stdout.push(chunk)
      },
      stderr: function(chunk) {
        data.stderr.push(chunk)
      },
      exit: function() {
        if (options.stream === 'stdout') {
          if (data.stderr.length && options.throwOnStdErr) {
            reject(new Error(data.stderr.join('')))
          } else {
            resolve(data.stdout.join(''))
          }
        } else if (options.stream === 'stderr') {
          resolve(data.stderr.join(''))
        } else {
          resolve({stdout: data.stdout.join(''), stderr: data.stderr.join('')})
        }
      }
    }
    const spawnedProcess = isNode ?
      new BufferedNodeProcess(parameters) :
      new BufferedProcess(parameters)

    spawnedProcess.onWillThrowError(function({error, handle}) {
      if (error.code !== 'ENOENT') {
        handle()
      }
      if (error.code === 'EACCES') {
        const newError = new Error(`Failed to spawn command '${command}'. Make sure it's a file, not a directory and it's executable.`)
        newError.name = 'BufferedProcessError'
        reject(newError)
      }
      reject(error)
    })

    if (options.stdin) {
      try {
        spawnedProcess.process.stdin.write(options.stdin.toString())
        spawnedProcess.process.stdin.end()
      } catch (_) {}
    }
  })
}

export function exec(command, args, options) {
  if (!arguments.length) {
    throw new Error('Nothing to execute')
  }
  return _exec(command, args, options, false)
}

export function execNode(command, args, options) {
  if (!arguments.length) {
    throw new Error('Nothing to execute')
  }
  return _exec(command, args, options, true)
}

@@ -2463,12 +2463,1054 @@
 ns, true)%0A%7D%0A
+%0Aexport function rangeFromLineNumber(textEditor, lineNumber, colStart) %7B%0A  if (typeof textEditor.getText !== 'function') %7B%0A    throw new Error('Invalid textEditor provided')%0A  %7D%0A%0A  if (typeof lineNumber !== 'number' %7C%7C lineNumber !== lineNumber %7C%7C lineNumber %3C 0) %7B%0A    return %5B%5B0, 0%5D, %5B0, 1%5D%5D%0A  %7D%0A%0A  const buffer = textEditor.getBuffer()%0A  const lineMax = buffer.getLineCount() - 1%0A%0A  if (lineNumber %3E lineMax) %7B%0A    throw new Error(%60Line number ($%7BlineNumber%7D) greater than maximum line ($%7BlineMax%7D)%60)%0A  %7D%0A%0A  if (typeof colStart !== 'number' %7C%7C colStart !== colStart %7C%7C colStart %3C 0) %7B%0A    const indentation = buffer.lineForRow(lineNumber).match(/%5E%5Cs+/)%0A    if (indentation && indentation.length) %7B%0A      colStart = indentation%5B0%5D.length%0A    %7D else %7B%0A      colStart = 0%0A    %7D%0A  %7D%0A%0A  const lineLength = buffer.lineLengthForRow(lineNumber)%0A%0A  if (colStart %3E lineLength) %7B%0A    throw new Error(%60Column start ($%7BcolStart%7D) greater than line length ($%7BlineLength%7D)%60)%0A  %7D%0A%0A  return %5B%0A    %5BlineNumber, colStart%5D,%0A    %5BlineNumber, lineLength%5D%0A  %5D%0A%7D%0A

Add rangeFromLineNumber helper