<commit_before>'use babel'

import {Range} from 'atom'
import promisify from 'sb-promisify'

const FS = require('fs')
const MESSAGE_EXTRACTION_REGEXP = /[\S ]+: ([\S ]+)\(/

export const readFile = promisify(FS.readFile)
export const realPath = promisify(FS.realpath)

export function fileExists(filePath, fail = true) {
  return new Promise(function(resolve, reject) {
    FS.access(filePath, FS.R_OK, function(error) {
      if (error && fail) {
        reject(error)
      } else resolve(error === null)
    })
  })
}

export function showError(message, detail = null) {
  if (message instanceof Error) {
    detail = message.stack
    message = message.message
  }
  atom.notifications.addError(`[Flint] ${message}`, {
    detail: detail,
    dismissable: true
  })
}

export function getMessage(error) {
  const matches = MESSAGE_EXTRACTION_REGEXP.exec(error.message)
  if (matches === null) {
    return error.message
  } else {
    return matches[1]
  }
}

export function getStatusText(status) {
  switch(status) {
    case WebSocket.OPEN:
      return 'Connected';
    case WebSocket.CLOSED:
      return 'Disconnected';
    case WebSocket.CONNECTING:
      return 'Connecting';
    default:
      console.debug('[Flint] Unknown websocket status', status)
      return 'Unknown'
  }
}

export function debounce(callback, delay) {
  let timeout = null
  return function(arg) {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      callback.call(this, arg)
    }, delay)
  }
}

export function aggressiveDebounce(callback, delay) {
  let timeout = null
  let latestArg = null
  return function(_) {
    latestArg = _
    if (timeout === null) {
      timeout = setTimeout(() => {
        timeout = null
        callback.call(this, latestArg)
      }, delay)
    }
  }
}

export function pointInRange(point, range) {
  return point.isGreaterThanOrEqual(range[0]) && point.isLessThanOrEqual(range[1])
}<commit_msg>:new: Add ensureUninstalled helper<commit_after>'use babel'

import {spawn} from 'child_process'
import {Range} from 'atom'
import promisify from 'sb-promisify'

const FS = require('fs')
const MESSAGE_EXTRACTION_REGEXP = /[\S ]+: ([\S ]+)\(/

export const readFile = promisify(FS.readFile)
export const realPath = promisify(FS.realpath)

export function fileExists(filePath, fail = true) {
  return new Promise(function(resolve, reject) {
    FS.access(filePath, FS.R_OK, function(error) {
      if (error && fail) {
        reject(error)
      } else resolve(error === null)
    })
  })
}

export function showError(message, detail = null) {
  if (message instanceof Error) {
    detail = message.stack
    message = message.message
  }
  atom.notifications.addError(`[Flint] ${message}`, {
    detail: detail,
    dismissable: true
  })
}

export function getMessage(error) {
  const matches = MESSAGE_EXTRACTION_REGEXP.exec(error.message)
  if (matches === null) {
    return error.message
  } else {
    return matches[1]
  }
}

export function getStatusText(status) {
  switch(status) {
    case WebSocket.OPEN:
      return 'Connected';
    case WebSocket.CLOSED:
      return 'Disconnected';
    case WebSocket.CONNECTING:
      return 'Connecting';
    default:
      console.debug('[Flint] Unknown websocket status', status)
      return 'Unknown'
  }
}

export function debounce(callback, delay) {
  let timeout = null
  return function(arg) {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      callback.call(this, arg)
    }, delay)
  }
}

export function aggressiveDebounce(callback, delay) {
  let timeout = null
  let latestArg = null
  return function(_) {
    latestArg = _
    if (timeout === null) {
      timeout = setTimeout(() => {
        timeout = null
        callback.call(this, latestArg)
      }, delay)
    }
  }
}

export function pointInRange(point, range) {
  return point.isGreaterThanOrEqual(range[0]) && point.isLessThanOrEqual(range[1])
}

export function ensureUninstalled(name) {
  if (atom.packages.isPackageLoaded(name)) {
    atom.packages.deactivatePackage(name)

    const apm = atom.packages.getApmPath()
    spawn(apm, ['uninstall', '--hard', name])
    atom.notifications.addSuccess('[Flint] Automatic package removal', {detail: `The package ${name} was no longer required and has been removed automatically`})
  }
}
{'fraction_non_alphanumeric': 0.12473867595818815, 'fraction_numerical': 0.0013937282229965157, 'mean_word_length': 3.4900938477580814, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4283054', 'n_tokens_mistral': 1364, 'n_tokens_neox': 1357, 'n_words': 329}