<repo_name>KELiON/cerebro-mac-apps<file_sep>/Readme.md
# cerebro-mac-apps

> Plugin for searching and launching applications on MacOS [Cerebro app](http://www.cerebroapp.com)

Note: this plugin on MacOS works better, than `cerebro-basic-apps`.

![](screenshot.png)

## Usage
Search for any application on your machine.

## Features

* Use `enter` to launch application;
* Use `cmd/ctrl+r` to show application in Finder or files explorer;
* Shows icons for your applications.

## Related

* [Cerebro](http://github.com/KELiON/cerebro) – main repo for Cerebro app;
* [cerebro tools](http://github.com/KELiON/cerebro-tools) – package with tools to simplify package creation;

## License

MIT © [<NAME>](http://asubbotin.ru)
<file_sep>/scripts/debug
#!/bin/sh
if [[ $1 == "dev" ]]; then
	appname="Electron"
else
	appname="Cerebro"
fi

case "$(uname -s)" in

   Darwin)
     symlink="${HOME}/Library/Application Support/${appname}/plugins/node_modules/${PWD##*/}"
     trap "echo 'Deleting symlink' && rm -rf \"$symlink\"" SIGHUP SIGINT SIGTERM
     ;;

   Linux)
     symlink="${HOME}/.config/${appname}/plugins/node_modules/${PWD##*/}"
     trap "echo 'Deleting symlink' && rm -rf \"$symlink\"" HUP INT TERM
     ;;

   CYGWIN*|MINGW32*|MINGW64*|MSYS*)
     symlink="${APPDATA}\\${appname}\plugins\node_modules\\${PWD##*/}"
     trap "echo 'Deleting symlink' && rm -rf \"$symlink\"" SIGHUP SIGINT SIGTERM
     ;;

   *)
     echo "Unknown system. Please, open an issue in https://github.com/KELiON/cerebro-plugin/issues"
     exit
     ;;
esac

echo "Creating symlink: $symlink -> ${PWD}"
ln -s "${PWD}" "$symlink"
./node_modules/.bin/webpack --watch
<file_sep>/src/Preview/index.js
import React, { PropTypes } from 'react'
import { FileIcon } from 'cerebro-ui'
import FileDetails from './FileDetails'
import styles from './styles.css'

const Preview = ({ path, name }) => (
  <div>
    <div className={styles.previewIcon}>
      <FileIcon path={path} />
    </div>
    <div className={styles.previewName}>{name}</div>
    <FileDetails path={path} key={path} skipName />
  </div>
)

Preview.propTypes = {
  path: PropTypes.string,
  name: PropTypes.string,
}

export default Preview
<file_sep>/src/lib/mdfind.js
import flatten from 'lodash/flatten'
import { spawn } from 'child_process'
import path from 'path'
import { map, split, through } from 'event-stream'

const REAL_KEYS = {
  kMDItemDisplayName: 'name',
  kMDItemLastUsedDate: 'lastUsed',
  kMDItemUseCount: 'useCount'
}

/**
 * Parse mdfind result line to JS object
 *
 * @param  {String} line
 * @return {Object}
 */
function parseLine(line) {
  const attrs = line.split('   ')
  // First attr is always full path to the item
  const filePath = attrs.shift()
  const result = {
    path: filePath,
    filename: path.basename(filePath).replace(/\.app$/, '')
  }
  attrs.forEach(attr => {
    const [key, value] = attr.split(' = ')
    result[REAL_KEYS[key] || key] = getValue(value)
  })
  this.emit('data', result)
}

const getValue = (item) => {
  if (!item || item === '(null)') {
    return null
  } else if (item.startsWith('(\n    "') && item.endsWith('"\n)')) {
    const actual = item.slice(7, -3)
    const lines = actual.split('",\n    "')
    return lines
  }
  return item
}

const filterEmpty = (data, done) => {
  if (data === '') {
    done()
  } else {
    done(null, data)
  }
}

const makeArgs = (array, argName) => (
  flatten(array.map(item => [argName, item]))
)

export default function mdfind({
  query,
  attributes = Object.keys(REAL_KEYS),
  names = [],
  directories = [],
  live = false,
  interpret = false,
  limit
} = {}) {
  const dirArgs = makeArgs(directories, '-onlyin')
  const nameArgs = makeArgs(names, '-name')
  const attrArgs = makeArgs(attributes, '-attr')
  const interpretArgs = interpret ? ['-interpret'] : []
  const queryArgs = query ? [query] : []

  const args = ['-0'].concat(
    dirArgs,
    nameArgs,
    attrArgs,
    interpretArgs,
    live ? ['-live', '-reprint'] : [],
    queryArgs
  )

  const child = spawn('mdfind', args)

  let times = 0

  return {
    output: child.stdout
      .pipe(split('\0'))
      .pipe(map(filterEmpty))
      // eslint-disable-next-line func-names
      .pipe(through(function (data) {
        times += 1
        if (limit && times === limit) child.kill()
        if (limit && times > limit) return
        this.queue(data)
      }))
      .pipe(through(parseLine)),
    terminate: () => child.kill()
  }
}
