Full Code of JumpFm/jumpfm for AI

master c89609281b56 cached
41 files
84.8 KB
24.4k tokens
31 symbols
1 requests
Download .txt
Repository: JumpFm/jumpfm
Branch: master
Commit: c89609281b56
Files: 41
Total size: 84.8 KB

Directory structure:
gitextract_g_cm2yzf/

├── .gitignore
├── .travis.yml
├── .vscode/
│   └── cSpell.json
├── README.md
├── app.js
├── appveyor.yml
├── build/
│   └── superhero.png.icns
├── index.html
├── misc/
│   ├── ascii.txt
│   ├── cookbook.txt
│   ├── icons.awk
│   ├── icons.txt
│   ├── init-demo.sh
│   ├── link-all.sh
│   ├── modd.conf
│   ├── omg-ubunut.txt
│   └── reddit.txt
├── package.json
├── scss/
│   ├── _app.scss
│   ├── _classes.scss
│   ├── _colors.scss
│   ├── _dialog.scss
│   ├── _panel.scss
│   ├── _panels.scss
│   ├── _statusbar.scss
│   ├── _tooltip.scss
│   └── index.scss
├── ts/
│   ├── Dialog.ts
│   ├── Filter.ts
│   ├── Item.ts
│   ├── JumpFm.ts
│   ├── Panel.ts
│   ├── PluginManager.ts
│   ├── Settings.ts
│   ├── StatusBar.ts
│   ├── files.ts
│   ├── icons.ts
│   ├── main.ts
│   └── shortway.ts
├── tsconfig.json
└── updates.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules/
dist/
.sass-cache/
css
_config.yml
js
*.swp
old
*.log


================================================
FILE: .travis.yml
================================================
sudo: required
dist: trusty
language: node_js
node_js: 6

branches:
  only:
  - master
  
before_install:
  - npm i -g npm@latest
  - npm i -g typescript
  - npm i -g node-sass

install:
  - npm i

cache:
  directories:
    - "node_modules"

env:
  global:
    - secure: >-
        QdHr5mVFKOyS/SmQPd7X6TOGhi4XhlJU+2w0O+RubOo/h2i1wLXD/f0DbAjEc0XfpTBSt9IDtUtqSuTi1YIUbafrqUwLFBUZ5VGYsPcMA48pD6+nzflMuaaCf//+pM8WtIAfgOK1i5k30faRzRnvSIYgX/Yyf4vS9j9OmfwD6342d1eD2b+h24R9z+eLlG9QaoJx9EAYhr1UAFbERiBlN40ThGU7uSkehzuYtGaQil8J8cV/MRqPCTSMAcZvpiUM7yGri11AWxJ5bOmyn7yVTFRBVWZDb4XaREXVTaEIXhvi/g+NO0e9WFETkw2cR7/Q6lw3kr/DqGz6Ks9XCOGppb1xILbvkUID/7pW+UKuzt6hc4AdoJLR+p0QtMWQn51oh1npGXzaMwjGGQ36gr+rdzc3Lukh08URzAFC2kywCg1sCsNCfoEH0hVD8OUhNQIkVOz530isjkZ8q9S1Us0ib5uviSZeA9XmfPBKe7aRxMY98WUvaeDCRmHqtmWy0nl9+ys4aI0197+4XlXijWeezd/ESLcWlZozKysAvTavC+hZPIBYz3Hpd6JOVzDGDgxWTpF91nCOJ+/gz/kHztAcaIC/iIVwIH4NhovuZ8t0kCKraEOWCnVkrikw9yK8unxgQfGWqU38ywUR7dN5if+u6Y67ih4ASnJ/LCqvUQvzy1o=

before_script:
  - tsc
  - node-sass scss -o css

script:
  - npm run publish



================================================
FILE: .vscode/cSpell.json
================================================
// cSpell Settings
{
    // Version of the setting file.  Always 0.1
    "version": "0.1",
    // language - current active spelling language
    "language": "en",
    // words - list of words to be always considered correct
    "words": [
        "Msgs",
        "jumpfm",
        "keyboardjs",
        "keycode",
        "pagedown",
        "pageup",
        "shortway"
    ],
    // flagWords - list of words to be always considered incorrect
    // This is useful for offensive words and common spelling errors.
    // For example "hte" should be "the"
    "flagWords": [
        "hte"
    ]
}

================================================
FILE: README.md
================================================
[![Build Status](https://travis-ci.org/Gilad-Kutiel-App/jumpfm.svg?branch=master)](https://travis-ci.org/Gilad-Kutiel-App/jumpfm)  [![Build status](https://ci.appveyor.com/api/projects/status/g9ggpk5578fq56x2?svg=true)](https://ci.appveyor.com/project/gkutiel/jumpfm) 

# About

JumpFm is a cross platform<sup>1,2</sup> dual panel file manager with builtin superpowers. 

----
<sup>1</sup>
Windows built is not tested at all, install it at your own risk

<sup>2</sup>
For a Mac release see [this fork](https://github.com/heywoodlh/jumpfm)

# \<dev/\>

## tl;dr.<sup>1,2</sup>
```
git clone git@github.com:Gilad-Kutiel-App/jumpfm.git
npm i -g typescript electron
cd jumpfm
npm i
tsc -w
sass --watch scss:css
electron .
```
---
<sup>1</sup>
You might want to [change npm's default directory](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-2-change-npms-default-directory-to-another-directory)

<sup>2</sup>
Use different terminal for each of  ```tsc -w```, ```sass --watch scss:css```, ```electron .```

## More \<dev/\>

JumpFm is an [Electron](https://electron.atom.io/) based app.
It is written in [TypeScript](https://www.typescriptlang.org/).
To hack the code all you need is [node.js](https://nodejs.org/en/) a
[decent editor](http://bit.ly/2wHIoSz) and a [sass compiler](http://sass-lang.com/).
This is how your terminal should looks like:

![](/misc/dev.png)





================================================
FILE: app.js
================================================
const updater = require('electron-simple-updater');
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')

// const log = require('electron-log');

app.on('window-all-closed', function() {
    if (process.platform != 'darwin') {
        app.quit();
    }
});

app.on('ready', function() {
    updater.init(
        'https://raw.githubusercontent.com/Gilad-Kutiel-App/jumpfm/master/updates.json'
    );

    const { width, height } = electron.screen.getPrimaryDisplay().workAreaSize;
    const w = parseInt(width * .8);
    const h = parseInt(height * .8);

    global.argv = process.argv
        // log.transports.file.level = 'debug';
        // log.transports.console.level = 'debug';

    // Create the browser window.
    let mainWindow = new BrowserWindow({
        width: w,
        height: h,
        icon: path.join(__dirname, 'build/icons/64x64.png'),
    });

    // mainWindow.setMenu(null);
    mainWindow.loadURL('file://' + __dirname + '/index.html');

    mainWindow.on('closed', function() {
        mainWindow = null;
    });
});

================================================
FILE: appveyor.yml
================================================
os: unstable
branches:
  only:
  - master

cache:
  - node_modules
environment:
  GH_TOKEN:
      secure: RcYdy07RY6uQXRBSJWfJfNG7FzZd7Y62IOTQ1n1pYjKTh9sgklNfNB9DBHZdOCzA
  matrix:
    - nodejs_version: 6
install:
  - ps: Install-Product node $env:nodejs_version
  - set CI=true
  - npm install -g npm@latest
  - npm i -g typescript
  - npm i -g node-sass 
  - set PATH=%APPDATA%\npm;%PATH%
  - npm install
matrix:
  fast_finish: true
build: off
version: '{build}'
shallow_clone: true
clone_depth: 1
test_script:
  - tsc
  - node-sass scss -o css
  - npm run publish

================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html>

<head>
  <title>JumpFm</title>
  <link rel="stylesheet"
    href="css/index.css">
  <link rel="stylesheet"
    href="font-awesome.min.css">

  <script src="js/main.js"></script>
</head>

<body>
  <div id="app"
    v-bind:style="{ fontSize: fontSize + 'px' }">

    <!-- DIALOG -->
    <div id='dialog'>
      <div id='dialog-content'>
        <div id='dialog-left'>
          <div id='dialog-label'></div>
        </div>
        <div id='dialog-right'>
          <input id="dialog-input"
            type="text" />
          <ol id='dialog-sug'
            class='border'>
            <li v-for="(sug, i) in dialog.sug"
              :cur="i == dialog.cur"
              v-html="sug.html" />
          </ol>
        </div>
      </div>
    </div>
    <!-- /DIALOG -->

    <!-- PANELS  -->
    <div id='panels'></div>
    <!-- /PANELS -->

    <!-- STATUS BAR  -->
    <footer id="statusbar">

      <!-- MSGS  -->
      <div id="statusbar-msgs"></div>

      <!-- BUTTONS  -->
      <div id="statusbar-buttons"></div>
    </footer>
    <!-- /STATUS BAR  -->
  </div>
</body>

================================================
FILE: misc/ascii.txt
================================================


       _                       ______          
      | |                     |  ____|         
      | |_   _ _ __ ___  _ __ | |__ _ __ ___   
  _   | | | | | '_ ` _ \| '_ \|  __| '_ ` _ \  
 | |__| | |_| | | | | | | |_) | |  | | | | | | 
  \____/ \__,_|_| |_| |_| .__/|_|  |_| |_| |_| 
                        | |                    
                        |_|                    




================================================
FILE: misc/cookbook.txt
================================================
find {{pwd}} -name {{input}}
find {{sel}} -name {{input}}
cat ~/favorits.txt

================================================
FILE: misc/icons.awk
================================================
#!/usr/bin/awk -f
BEGIN { 
	RS="}"
	print "{"
}

match($0, /icon: '([^']+)'.*extensions: (\[[^\].]+\])/, a){
	print "\""a[1]"\"", ":", gensub(/'/,"\"", "g", a[2])","
}	

match($0, /icon: '([^']+)'.*languages: (\[[^\]]+\])/, a){
	print "\""a[1]"\"", ":", gensub(/languages\.(\w+)/, "\"\\1\"", "g", a[2])","
}	

END {
	print "}"
}


================================================
FILE: misc/icons.txt
================================================
/* tslint:disable max-line-length */
import { languages } from './languages';
import { FileFormat, IFileCollection } from '../models';

export const extensions: IFileCollection = {
  default: {
    file: { icon: 'file', format: FileFormat.svg },
  },
  supported: [
    { icon: 'access', extensions: ['accdb', 'accdt', 'mdb', 'accda', 'accdc', 'accde', 'accdp', 'accdr', 'accdu', 'ade', 'adp', 'laccdb', 'ldb', 'mam', 'maq', 'mdw'], format: FileFormat.svg },
    { icon: 'actionscript', extensions: [], languages: [languages.actionscript], format: FileFormat.svg },
    { icon: 'ai', extensions: ['ai'], format: FileFormat.svg },
    { icon: 'ai2', extensions: ['ai'], format: FileFormat.svg, disabled: true },
    { icon: 'org', extensions: ['org'], format: FileFormat.svg },
    { icon: 'angular', extensions: ['.angular-cli.json', 'angular-cli.json'], filename: true, format: FileFormat.svg },
    { icon: 'ng_component_ts', extensions: ['component.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_component_js', extensions: ['component.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_controller_ts', extensions: ['controller.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_controller_js', extensions: ['controller.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_directive_ts', extensions: ['directive.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_directive_js', extensions: ['directive.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_guard_ts', extensions: ['guard.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_guard_js', extensions: ['guard.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_module_ts', extensions: ['module.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_module_js', extensions: ['module.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_pipe_ts', extensions: ['pipe.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_pipe_js', extensions: ['pipe.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_ts', extensions: ['routing.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_js', extensions: ['routing.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_ts', extensions: ['app-routing.module.ts'], filename: true, format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_js', extensions: ['app-routing.module.js'], filename: true, format: FileFormat.svg, disabled: true },
    { icon: 'ng_smart_component_ts', extensions: ['page.ts', 'container.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_smart_component_js', extensions: ['page.js', 'container.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_service_ts', extensions: ['service.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_service_js', extensions: ['service.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_component_ts2', extensions: ['component.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_component_js2', extensions: ['component.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_directive_ts2', extensions: ['directive.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_directive_js2', extensions: ['directive.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_module_ts2', extensions: ['module.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_module_js2', extensions: ['module.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_pipe_ts2', extensions: ['pipe.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_pipe_js2', extensions: ['pipe.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_ts2', extensions: ['routing.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_js2', extensions: ['routing.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_ts2', extensions: ['app-routing.module.ts'], filename: true, format: FileFormat.svg, disabled: true },
    { icon: 'ng_routing_js2', extensions: ['app-routing.module.js'], filename: true, format: FileFormat.svg, disabled: true },
    { icon: 'ng_smart_component_ts2', extensions: ['page.ts', 'container.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_smart_component_js2', extensions: ['page.js', 'container.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_service_ts2', extensions: ['service.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'ng_service_js2', extensions: ['service.js'], format: FileFormat.svg, disabled: true },
    { icon: 'ansible', extensions: [], languages: [languages.ansible], format: FileFormat.svg },
    { icon: 'anyscript', extensions: [], languages: [languages.anyscript], format: FileFormat.svg },
    { icon: 'apache', extensions: [], languages: [languages.apache], format: FileFormat.svg },
    { icon: 'apib', extensions: [], languages: [languages.apib], format: FileFormat.svg },
    { icon: 'applescript', extensions: [], languages: [languages.applescript], format: FileFormat.svg },
    { icon: 'appveyor', extensions: ['appveyor.yml', '.appveyor.yml'], filename: true, format: FileFormat.svg },
    { icon: 'asp', extensions: [], languages: [languages.asp], format: FileFormat.svg },
    { icon: 'aspx', extensions: ['aspx', 'ascx'], format: FileFormat.svg },
    { icon: 'assembly', extensions: [], languages: [languages.assembly], format: FileFormat.svg },
    { // https://en.wikipedia.org/wiki/Audio_file_format
      icon: 'audio',
      extensions: ['aac', 'act', 'aiff', 'amr', 'ape', 'au', 'dct', 'dss', 'dvf', 'flac', 'gsm',
        'iklax', 'ivs', 'm4a', 'm4b', 'm4p', 'mmf', 'mogg', 'mp3', 'mpc', 'msv', 'oga', 'ogg', 'opus',
        'ra', 'raw', 'tta', 'vox', 'wav', 'wma'],
      format: FileFormat.svg,
    },
    { icon: 'aurelia', extensions: ['aurelia.json'], filename: true, format: FileFormat.svg },
    { icon: 'autohotkey', extensions: [], languages: [languages.autohotkey], format: FileFormat.svg },
    { icon: 'autoit', extensions: [], languages: [languages.autoit], format: FileFormat.svg },
    { icon: 'aws', extensions: [], format: FileFormat.svg },
    { icon: 'babel', extensions: ['.babelrc', 'babelrc.js'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'babel2', extensions: ['.babelrc', 'babelrc.js'], light: true, filename: true, format: FileFormat.svg, disabled: true },
    { icon: 'bat', extensions: [], languages: [languages.bat], format: FileFormat.svg },
    { // http://www.file-extensions.org/filetype/extension/name/binary-files
      icon: 'binary',
      extensions: ['a', 'app', 'bin', 'cmo', 'cmx', 'cma', 'cmxa', 'cmi', 'dll', 'exe', 'hl', 'ilk',
        'lib', 'n', 'ndll', 'o', 'obj', 'pyc', 'pyd', 'pyo', 'pdb', 'scpt', 'scptd', 'so'],
      format: FileFormat.svg,
    },
    { icon: 'bithound', extensions: ['.bithoundrc'], filename: true, format: FileFormat.svg },
    { icon: 'blade', extensions: [], languages: [languages.blade], format: FileFormat.svg },
    { icon: 'bolt', extensions: [], languages: [languages.bolt], filename: true, format: FileFormat.svg },
    { icon: 'bower', extensions: ['.bowerrc', 'bower.json'], filename: true, format: FileFormat.svg },
    { icon: 'buckbuild', extensions: ['.buckconfig'], filename: true, format: FileFormat.svg },
    { icon: 'bundler', extensions: ['gemfile', 'gemfile.lock'], filename: true, format: FileFormat.svg },
    { icon: 'c', extensions: [], languages: [languages.c], format: FileFormat.svg },
    { icon: 'c2', extensions: [], languages: [languages.c], format: FileFormat.svg, disabled: true },
    { icon: 'cabal', extensions: [], languages: [languages.cabal], format: FileFormat.svg },
    { icon: 'cake', extensions: [], languages: [languages.cake], format: FileFormat.svg },
    { icon: 'cakephp', extensions: [], format: FileFormat.svg },
    { icon: 'cert', extensions: ['csr', 'crt', 'cer', 'der', 'pfx', 'p12', 'p7b', 'p7r', 'src', 'crl', 'sst', 'stl'], format: FileFormat.svg },
    { icon: 'cf', extensions: ['lucee'], languages: [languages.coldfusion], format: FileFormat.svg },
    { icon: 'cf2', extensions: ['lucee'], languages: [languages.coldfusion], format: FileFormat.svg, disabled: true },
    { icon: 'cfc', extensions: [], languages: [languages.cfc], format: FileFormat.svg },
    { icon: 'cfc2', extensions: [], languages: [languages.cfc], format: FileFormat.svg, disabled: true },
    { icon: 'cfm', extensions: [], languages: [languages.cfm], format: FileFormat.svg },
    { icon: 'cfm2', extensions: [], languages: [languages.cfm], format: FileFormat.svg, disabled: true },
    { icon: 'cheader', extensions: ['h'], format: FileFormat.svg },
    { icon: 'chef', extensions: ['chefignore', 'berksfile', 'berksfile.lock', 'policyfile'], filename: true, format: FileFormat.svg },
    { icon: 'class', extensions: ['class'], format: FileFormat.svg },
    { icon: 'circleci', extensions: ['circle.yml'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'clojure', extensions: ['cjm', 'cljc'], languages: [languages.clojure], format: FileFormat.svg },
    { icon: 'cmake', extensions: [], languages: [languages.cmake, languages.cmakecache], format: FileFormat.svg },
    { icon: 'cobol', extensions: [], languages: [languages.cobol], format: FileFormat.svg },
    { icon: 'codeclimate', extensions: ['.codeclimate.yml'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'codecov', extensions: ['codecov.yml', '.codecov.yml'], filename: true, format: FileFormat.svg },
    { icon: 'codekit', extensions: ['kit'], format: FileFormat.svg },
    { icon: 'codekit', extensions: ['config.codekit', 'config.codekit2', 'config.codekit3'], filename: true, format: FileFormat.svg },
    { icon: 'coffeescript', extensions: [], languages: [languages.coffeescript], format: FileFormat.svg },
    { icon: 'config', extensions: ['env'], light: true, languages: [languages.properties], format: FileFormat.svg },
    { icon: 'config', extensions: ['.env.example'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'compass', extensions: [], format: FileFormat.svg },
    { icon: 'composer', extensions: ['composer.json', 'composer.lock'], filename: true, format: FileFormat.svg },
    { icon: 'cpp', extensions: [], languages: [languages.cpp], format: FileFormat.svg },
    { icon: 'cpp2', extensions: [], languages: [languages.cpp], format: FileFormat.svg, disabled: true },
    { icon: 'cppheader', extensions: ['hpp'], format: FileFormat.svg },
    { icon: 'crystal', extensions: [], languages: [languages.crystal], format: FileFormat.svg },
    { icon: 'csharp', extensions: ['csx'], languages: [languages.csharp], format: FileFormat.svg },
    { icon: 'csproj', extensions: ['csproj'], format: FileFormat.svg },
    { icon: 'css', extensions: [], languages: [languages.css], format: FileFormat.svg },
    { icon: 'csslint', extensions: ['.csslintrc'], filename: true, format: FileFormat.svg },
    { icon: 'cssmap', extensions: ['css.map'], format: FileFormat.svg },
    { icon: 'cucumber', extensions: [], languages: [languages.cucumber], format: FileFormat.svg },
    { icon: 'dartlang', extensions: [], languages: [languages.dart], format: FileFormat.svg },
    { icon: 'db', extensions: ['db'], light: true, format: FileFormat.svg },
    { icon: 'delphi', extensions: [], languages: [languages.pascal], format: FileFormat.svg },
    { icon: 'dlang', extensions: [], languages: [languages.dlang], format: FileFormat.svg },
    { icon: 'diff', extensions: [], languages: [languages.diff], format: FileFormat.svg },
    { icon: 'docker', extensions: ['.dockerignore', 'docker-compose.yml', 'docker-compose.ci-build.yml', 'docker-compose.override.yml', 'docker-compose.vs.debug.yml', 'docker-compose.vs.release.yml', 'docker-cloud.yml'], filename: true, languages: [languages.dockerfile], format: FileFormat.svg },
    { icon: 'docker2', extensions: ['.dockerignore', 'docker-compose.yml', 'docker-compose.ci-build.yml', 'docker-compose.override.yml', 'docker-compose.vs.debug.yml', 'docker-compose.vs.release.yml', 'docker-cloud.yml'], filename: true, languages: [languages.dockerfile], format: FileFormat.svg, disabled: true },
    { icon: 'doxygen', extensions: [], languages: [languages.doxygen], format: FileFormat.svg },
    { icon: 'drone', extensions: ['.drone.yml', '.drone.yml.sig'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'editorconfig', extensions: ['.editorconfig'], filename: true, format: FileFormat.svg },
    { icon: 'ejs', extensions: ['ejs'], format: FileFormat.svg },
    { icon: 'elasticbeanstalk', extensions: [], format: FileFormat.svg },
    { icon: 'elixir', extensions: [], languages: [languages.elixir], format: FileFormat.svg },
    { icon: 'elm', extensions: ['elm-package.json'], filename: true, languages: [languages.elm], format: FileFormat.svg },
    { icon: 'elm2', extensions: ['elm-package.json'], filename: true, languages: [languages.elm], format: FileFormat.svg, disabled: true },
    { icon: 'emacs', extensions: ['el', 'elc'], format: FileFormat.svg },
    { icon: 'ember', extensions: ['.ember-cli'], filename: true, format: FileFormat.svg },
    { icon: 'ensime', extensions: ['ensime'], format: FileFormat.svg },
    { icon: 'eps', extensions: ['eps'], format: FileFormat.svg },
    { icon: 'erb', extensions: [], languages: [languages.erb], format: FileFormat.svg },
    { icon: 'erlang', extensions: ['emakefile', '.emakerfile'], filename: true, languages: [languages.erlang], format: FileFormat.svg },
    { icon: 'eslint', extensions: ['.eslintrc', '.eslintignore', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yaml', '.eslintrc.yml'], filename: true, format: FileFormat.svg },
    { icon: 'eslint2', extensions: ['.eslintrc', '.eslintignore', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yaml', '.eslintrc.yml'], filename: true, format: FileFormat.svg, disabled: true },
    { icon: 'excel', extensions: ['xls', 'xlsx', 'xlsm', 'ods'], format: FileFormat.svg },
    { icon: 'favicon', extensions: ['favicon.ico'], filename: true, format: FileFormat.svg },
    { icon: 'firebase', extensions: ['.firebaserc'], filename: true, format: FileFormat.svg },
    { icon: 'flash', extensions: ['swf', 'swc'], format: FileFormat.svg },
    { icon: 'flow', extensions: ['js.flow'], format: FileFormat.svg },
    { icon: 'flow', extensions: ['.flowconfig'], filename: true, format: FileFormat.svg },
    { icon: 'font', extensions: ['woff', 'woff2', 'ttf', 'otf', 'eot', 'pfa', 'pfb', 'sfd'], light: true, format: FileFormat.svg },
    { icon: 'fortran', extensions: [], languages: [languages.fortran], format: FileFormat.svg },
    { icon: 'fsharp', extensions: [], languages: [languages.fsharp], format: FileFormat.svg },
    { icon: 'fsproj', extensions: ['fsproj'], format: FileFormat.svg },
    { icon: 'freemarker', extensions: [], languages: [languages.freemarker], format: FileFormat.svg },
    { icon: 'fusebox', extensions: ['fuse.js'], filename: true, format: FileFormat.svg },
    { icon: 'galen', extensions: [], languages: [languages.galen], format: FileFormat.svg },
    { icon: 'galen2', extensions: [], languages: [languages.galen], format: FileFormat.svg, disabled: true },
    { icon: 'git', extensions: ['.gitattributes', '.gitconfig', '.gitignore', '.gitmodules', '.gitkeep'], filename: true, languages: [languages.git], format: FileFormat.svg },
    { icon: 'gamemaker', extensions: ['gmx'], languages: [languages.gamemaker], format: FileFormat.svg },
    { icon: 'gamemaker2', extensions: ['yy', 'yyp'], light: true, languages: [languages.gamemaker2], format: FileFormat.svg },
    { icon: 'gamemaker81', extensions: [], languages: [languages.gamemaker81], format: FileFormat.svg },
    { icon: 'gitlab', extensions: ['.gitlab-ci.yml'], filename: true, format: FileFormat.svg },
    { icon: 'glsl', extensions: [], languages: [languages.glsl], format: FileFormat.svg },
    { icon: 'go', extensions: [], languages: [languages.go], format: FileFormat.svg },
    { icon: 'godot', extensions: [], languages: [languages.godot], format: FileFormat.svg },
    { icon: 'gradle', extensions: ['gradle'], format: FileFormat.svg },
    { icon: 'graphql', extensions: ['.gqlconfig'], filename: true, languages: [languages.graphql], format: FileFormat.svg },
    { icon: 'graphviz', extensions: [], languages: [languages.graphviz], format: FileFormat.svg },
    { icon: 'groovy', extensions: [], languages: [languages.groovy], format: FileFormat.svg },
    { icon: 'groovy2', extensions: [], languages: [languages.groovy], format: FileFormat.svg, disabled: true },
    {
      icon: 'grunt', extensions: [
        'gruntfile.coffee',
        'gruntfile.babel.coffee',
        'gruntfile.js',
        'gruntfile.babel.js',
        'gruntfile.ts',
        'gruntfile.babel.ts',
      ],
      filename: true, format: FileFormat.svg,
    },
    {
      icon: 'gulp', extensions: [
        'gulpfile.coffee',
        'gulpfile.babel.coffee',
        'gulpfile.js',
        'gulpfile.babel.js',
        'gulpfile.ts',
        'gulpfile.babel.ts',
      ],
      filename: true, format: FileFormat.svg,
    },
    { icon: 'haml', extensions: [], languages: [languages.haml], format: FileFormat.svg },
    { icon: 'handlebars', extensions: [], languages: [languages.handlebars], format: FileFormat.svg },
    { icon: 'handlebars2', extensions: [], languages: [languages.handlebars], format: FileFormat.svg, disabled: true },
    { icon: 'harbour', extensions: [], languages: [languages.harbour], format: FileFormat.svg },
    { icon: 'haskell', extensions: [], languages: [languages.haskell, languages.literatehaskell], format: FileFormat.svg },
    { icon: 'haskell2', extensions: [], languages: [languages.haskell, languages.literatehaskell], format: FileFormat.svg, disabled: true },
    { icon: 'haxe', extensions: ['haxelib.json'], filename: true, languages: [languages.haxe], format: FileFormat.svg },
    { icon: 'haxecheckstyle', extensions: ['checkstyle.json'], filename: true, format: FileFormat.svg },
    { icon: 'haxedevelop', extensions: ['hxproj'], format: FileFormat.svg },
    { icon: 'hlsl', extensions: [], languages: [languages.hlsl], format: FileFormat.svg },
    { icon: 'html', extensions: [], languages: [languages.html], format: FileFormat.svg },
    { icon: 'idris', extensions: ['idr', 'lidr'], format: FileFormat.svg },
    { icon: 'idrisbin', extensions: ['ibc'], format: FileFormat.svg },
    { icon: 'idrispkg', extensions: ['ipkg'], format: FileFormat.svg },
    { icon: 'image', extensions: ['jpeg', 'jpg', 'gif', 'png', 'bmp', 'tiff', 'ico'], format: FileFormat.svg },
    { icon: 'ini', extensions: [], languages: [languages.ini], light: true, format: FileFormat.svg },
    { icon: 'infopath', extensions: ['infopathxml', 'xsn', 'xsf', 'xtp2'], format: FileFormat.svg },
    { icon: 'ionic', extensions: ['ionic.project', 'ionic.config.json'], filename: true, format: FileFormat.svg },
    { icon: 'jar', extensions: ['jar'], format: FileFormat.svg },
    { icon: 'java', extensions: [], languages: [languages.java], format: FileFormat.svg },
    { icon: 'jbuilder', extensions: ['jbuilder'], format: FileFormat.svg },
    { icon: 'jenkins', extensions: ['jenkinsfile'], filename: true, format: FileFormat.svg },
    { icon: 'jest', extensions: ['jest.config.js', 'jest.json', 'jest.config.json', '.jestrc'], filename: true, format: FileFormat.svg },
    { icon: 'jinja', extensions: [], languages: [languages.jinja], format: FileFormat.svg },
    { icon: 'js', extensions: [], light: true, languages: [languages.javascript], format: FileFormat.svg },
    { icon: 'js_official', extensions: [], languages: [languages.javascript], format: FileFormat.svg, disabled: true },
    { icon: 'jsconfig', extensions: ['jsconfig.json'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'jshint', extensions: ['.jshintrc', '.jshintignore'], filename: true, format: FileFormat.svg },
    { icon: 'jsmap', extensions: ['js.map'], light: true, format: FileFormat.svg },
    { icon: 'json', extensions: [], light: true, languages: [languages.json, languages.textmatejson], format: FileFormat.svg },
    { icon: 'json_official', extensions: [], languages: [languages.json, languages.textmatejson], format: FileFormat.svg, disabled: true },
    { icon: 'json2', extensions: [], languages: [languages.json, languages.textmatejson], format: FileFormat.svg, disabled: true },
    { icon: 'jsonld', extensions: ['jsonld', 'json-ld'], light: true, format: FileFormat.svg },
    { icon: 'jsp', extensions: ['jsp'], format: FileFormat.svg },
    { icon: 'julia', extensions: [], languages: [languages.julia], format: FileFormat.svg },
    { icon: 'julia2', extensions: [], languages: [languages.julia], format: FileFormat.svg, disabled: true },
    { icon: 'karma', extensions: ['karma.conf.js', 'karma.conf.coffee'], filename: true, format: FileFormat.svg },
    { icon: 'key', extensions: ['key', 'pem'], format: FileFormat.svg },
    { icon: 'kite', extensions: ['.kiteignore'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'kitchenci', extensions: ['.kitchen.yml'], filename: true, format: FileFormat.svg },
    { icon: 'kotlin', extensions: [], languages: [languages.kotlin], format: FileFormat.svg },
    { icon: 'layout', extensions: ['master', 'layout.html', 'layout.htm'], format: FileFormat.svg },
    { icon: 'layout', extensions: ['layout.html', 'layout.htm'], filename: true, format: FileFormat.svg },
    { icon: 'lerna', extensions: ['lerna.json'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'less', extensions: [], languages: [languages.less], format: FileFormat.svg },
    { icon: 'license', extensions: ['enc'], format: FileFormat.svg },
    { icon: 'license', extensions: ['license', 'licence', 'license.md', 'licence.md', 'license.txt', 'licence.txt'], filename: true, format: FileFormat.svg },
    { icon: 'lisp', extensions: [], languages: [languages.lisp], format: FileFormat.svg },
    { icon: 'lime', extensions: ['hxp'], format: FileFormat.svg },
    { icon: 'lime', extensions: ['include.xml'], filename: true, format: FileFormat.svg },
    { icon: 'liquid', extensions: ['liquid'], format: FileFormat.svg },
    { icon: 'locale', extensions: [], format: FileFormat.svg },
    { icon: 'log', extensions: ['log'], format: FileFormat.svg },
    { icon: 'lsl', extensions: ['lsl'], format: FileFormat.svg },
    { icon: 'lua', extensions: [], languages: [languages.lua], format: FileFormat.svg },
    { icon: 'lync', extensions: ['crec', 'ocrec'], format: FileFormat.svg },
    { icon: 'makefile', extensions: ['makefile'], format: FileFormat.svg },
    { icon: 'makefile', extensions: [], languages: [languages.makefile], format: FileFormat.svg },
    { icon: 'map', extensions: ['map'], format: FileFormat.svg },
    { icon: 'markdown', extensions: ['mdown', 'markdown'], languages: [languages.markdown], format: FileFormat.svg },
    { icon: 'markdownlint', extensions: ['.markdownlint.json'], filename: true, format: FileFormat.svg },
    { icon: 'marko', extensions: [], languages: [languages.marko], format: FileFormat.svg },
    { icon: 'markojs', extensions: ['marko.js'], format: FileFormat.svg },
    { icon: 'matlab', extensions: ['fig', 'mex', 'mexn', 'mexrs6', 'mn', 'mum', 'mx', 'mx3', 'rwd', 'slx', 'slddc', 'smv', 'tikz', 'xvc'], languages: [languages.matlab], format: FileFormat.png },
    { icon: 'meteor', extensions: [], format: FileFormat.svg },
    { icon: 'mjml', extensions: [], languages: [languages.mjml], format: FileFormat.svg },
    { icon: 'mustache', extensions: ['mustache', 'mst'], light: true, format: FileFormat.svg },
    { icon: 'nim', extensions: [], languages: [languages.nim], format: FileFormat.svg },
    { icon: 'njsproj', extensions: ['njsproj'], format: FileFormat.svg },
    { icon: 'node', extensions: ['.nvmrc'], filename: true, format: FileFormat.svg },
    { icon: 'node2', extensions: [], format: FileFormat.svg, disabled: true },
    { icon: 'npm', extensions: ['.npmignore', '.npmrc', 'package.json', 'package-lock.json'], filename: true, format: FileFormat.svg },
    { icon: 'nsi', extensions: [], languages: [languages.nsis], format: FileFormat.svg },
    { icon: 'nuget', extensions: ['nupkg', 'nuspec', 'psmdcp'], format: FileFormat.svg },
    { icon: 'nunjucks', extensions: ['nunj', 'njs'], languages: [languages.nunjucks], format: FileFormat.svg },
    { icon: 'objectivec', extensions: [], languages: [languages.objectivec], format: FileFormat.svg },
    { icon: 'objectivecpp', extensions: [], languages: [languages.objectivecpp], format: FileFormat.svg },
    { icon: 'ocaml', extensions: ['.merlin'], filename: true, languages: [languages.ocaml], format: FileFormat.svg },
    { icon: 'onenote', extensions: ['one', 'onepkg', 'onetoc', 'onetoc2', 'sig'], format: FileFormat.svg },
    { icon: 'opencl', extensions: ['cl', 'opencl'], format: FileFormat.svg },
    { icon: 'outlook', extensions: ['pst', 'bcmx', 'otm', 'msg', 'oft'], format: FileFormat.svg },
    { icon: 'package', extensions: ['pkg'], format: FileFormat.svg },
    { icon: 'paket', extensions: ['paket.dependencies', 'paket.lock', 'paket.references', 'paket.template', 'paket.local'], filename: true, format: FileFormat.svg },
    { icon: 'patch', extensions: ['patch'], format: FileFormat.svg },
    { icon: 'pcl', extensions: ['pcd'], light: true, format: FileFormat.svg },
    { icon: 'pdf', extensions: ['pdf'], format: FileFormat.svg },
    { icon: 'pdf2', extensions: ['pdf'], format: FileFormat.svg, disabled: true },
    { icon: 'perl', extensions: [], languages: [languages.perl], format: FileFormat.svg },
    { icon: 'perl2', extensions: [], languages: [languages.perl], format: FileFormat.svg, disabled: true },
    { icon: 'perl6', extensions: [], languages: [languages.perl6], format: FileFormat.svg },
    { icon: 'photoshop', extensions: ['psd'], format: FileFormat.svg },
    { icon: 'photoshop2', extensions: ['psd'], format: FileFormat.svg, disabled: true },
    { icon: 'php', extensions: ['php1', 'php2', 'php3', 'php4', 'php5', 'php6', 'phps', 'phpsa', 'phpt', 'phtml', 'phar'], languages: [languages.php], format: FileFormat.svg },
    { icon: 'php2', extensions: ['php1', 'php2', 'php3', 'php4', 'php5', 'php6', 'phps', 'phpsa', 'phpt', 'phtml', 'phar'], languages: [languages.php], format: FileFormat.svg, disabled: true },
    { icon: 'php3', extensions: ['php1', 'php2', 'php3', 'php4', 'php5', 'php6', 'phps', 'phpsa', 'phpt', 'phtml', 'phar'], languages: [languages.php], format: FileFormat.svg, disabled: true },
    { icon: 'phpunit', extensions: ['phpunit', 'phpunit.xml', 'phpunit.xml.dist'], filename: true, format: FileFormat.svg },
    { icon: 'plantuml', extensions: ['pu', 'plantuml', 'iuml', 'puml'], format: FileFormat.svg },
    { icon: 'plsql', extensions: [], languages: [languages.plsql], format: FileFormat.svg },
    { icon: 'plsql_package', extensions: ['pck'], format: FileFormat.svg },
    { icon: 'plsql_package_body', extensions: ['pkb'], format: FileFormat.svg },
    { icon: 'plsql_package_header', extensions: ['pkh'], format: FileFormat.svg },
    { icon: 'plsql_package_spec', extensions: ['pks'], format: FileFormat.svg },
    { icon: 'poedit', extensions: ['po', 'mo'], format: FileFormat.svg },
    { icon: 'polymer', extensions: [], languages: [languages.polymer], format: FileFormat.svg },
    { icon: 'postcss', extensions: ['.postcssrc.js', 'postcss.config.js'], filename: true, languages: [languages.postcss], format: FileFormat.svg },
    { icon: 'powerpoint', extensions: ['pot', 'potx', 'potm', 'pps', 'ppsx', 'ppsm', 'ppt', 'pptx', 'pptm', 'pa', 'ppa', 'ppam', 'sldm', 'sldx'], format: FileFormat.svg },
    { icon: 'powershell', extensions: [], languages: [languages.powershell], format: FileFormat.svg },
    { icon: 'procfile', extensions: ['procfile'], filename: true, format: FileFormat.svg },
    { icon: 'progress', extensions: [], languages: [languages.openEdge], format: FileFormat.svg },
    { icon: 'prolog', extensions: ['pro', 'P'], languages: [languages.prolog], format: FileFormat.svg },
    { icon: 'protobuf', extensions: [], languages: [languages.protobuf], format: FileFormat.svg },
    { icon: 'protractor', extensions: ['protractor.conf.js'], filename: true, format: FileFormat.svg },
    { icon: 'publisher', extensions: ['pub', 'puz'], format: FileFormat.svg },
    { icon: 'puppet', extensions: [], languages: [languages.puppet], format: FileFormat.svg },
    { icon: 'pug', extensions: ['.jade-lintrc', '.pug-lintrc', '.jade-lint.json', '.pug-lintrc.js', '.pug-lintrc.json'], filename: true, languages: [languages.pug], format: FileFormat.svg },
    { icon: 'purescript', extensions: [], light: true, languages: [languages.purescript], format: FileFormat.svg },
    { icon: 'python', extensions: [], languages: [languages.python], format: FileFormat.svg },
    { icon: 'qlikview', extensions: ['qvd', 'qvw'], languages: [languages.qlik], format: FileFormat.svg },
    { icon: 'r', extensions: [], languages: [languages.r], format: FileFormat.svg },
    { icon: 'rails', extensions: [], format: FileFormat.svg },
    { icon: 'rake', extensions: ['rake'], format: FileFormat.svg },
    { icon: 'rake', extensions: ['rakefile'], filename: true, format: FileFormat.svg },
    { icon: 'raml', extensions: [], languages: [languages.raml], format: FileFormat.svg },
    { icon: 'razor', extensions: [], languages: [languages.razor], format: FileFormat.svg },
    { icon: 'reactjs', extensions: [], languages: [languages.javascriptreact], format: FileFormat.svg },
    { icon: 'reacttemplate', extensions: ['rt'], format: FileFormat.svg },
    { icon: 'reactts', extensions: [], languages: [languages.typescriptreact], format: FileFormat.svg },
    { icon: 'reason', extensions: [], languages: [languages.reason], format: FileFormat.svg },
    { icon: 'rest', extensions: [], languages: [languages.restructuredtext], format: FileFormat.svg },
    { icon: 'registry', extensions: ['reg'], format: FileFormat.svg },
    { icon: 'riot', extensions: [], languages: [languages.riot], format: FileFormat.svg },
    { icon: 'robotframework', extensions: [], languages: [languages.robot], format: FileFormat.svg },
    { icon: 'rollup', extensions: ['rollup.config.js', 'rollup.config.ts'], filename: true, format: FileFormat.svg },
    { icon: 'rspec', extensions: ['.rspec'], filename: true, format: FileFormat.svg },
    { icon: 'ruby', extensions: [], languages: [languages.ruby], format: FileFormat.svg },
    { icon: 'rust', extensions: [], languages: [languages.rust], format: FileFormat.svg },
    { icon: 'saltstack', extensions: ['sls'], format: FileFormat.svg },
    { icon: 'sass', extensions: ['sass'], format: FileFormat.svg },
    { icon: 'sbt', extensions: [], languages: [languages.sbt], format: FileFormat.svg },
    { icon: 'scala', extensions: [], languages: [languages.scala], format: FileFormat.svg },
    { icon: 'script', extensions: [], languages: [languages.vbscript], format: FileFormat.svg },
    { icon: 'scss', extensions: ['scssm'], languages: [languages.scss], format: FileFormat.svg },
    { icon: 'sequelize', extensions: ['.sequelizerc'], filename: true, format: FileFormat.svg },
    { icon: 'shaderlab', extensions: [], languages: [languages.shaderlab], light: true, format: FileFormat.svg },
    { icon: 'shell', extensions: ['fish'], languages: [languages.shellscript], format: FileFormat.svg },
    { icon: 'slim', extensions: [], languages: [languages.slim], format: FileFormat.svg },
    { icon: 'sln', extensions: ['sln'], format: FileFormat.svg },
    { icon: 'smarty', extensions: [], languages: [languages.smarty], format: FileFormat.svg },
    { icon: 'snyk', extensions: ['.snyk'], filename: true, format: FileFormat.svg },
    { icon: 'solidity', extensions: [], light: true, languages: [languages.solidity], format: FileFormat.svg },
    { icon: 'source', extensions: [], format: FileFormat.svg },
    { icon: 'sqf', extensions: [], languages: [languages.sqf], format: FileFormat.svg },
    { icon: 'sql', extensions: [], languages: [languages.sql], format: FileFormat.svg },
    { icon: 'sqlite', extensions: ['sqlite', 'sqlite3', 'db3'], format: FileFormat.svg },
    { icon: 'sss', extensions: ['sss'], format: FileFormat.svg },
    { icon: 'style', extensions: [], format: FileFormat.svg },
    { icon: 'stylelint', extensions: ['.stylelintrc', 'stylelint.config.js', '.stylelintignore'], light: true, filename: true, format: FileFormat.svg },
    { icon: 'stylus', extensions: [], languages: [languages.stylus], format: FileFormat.svg },
    { icon: 'storyboard', extensions: ['storyboard'], format: FileFormat.svg },
    { icon: 'storybook', extensions: ['story.js', 'stories.js'], format: FileFormat.svg },
    { icon: 'svg', extensions: ['svg'], format: FileFormat.svg },
    { icon: 'swagger', extensions: [], languages: [languages.swagger], format: FileFormat.svg },
    { icon: 'swift', extensions: ['package.pins'], filename: true, languages: [languages.swift], format: FileFormat.svg },
    { icon: 'tcl', extensions: ['tcl', 'exp'], format: FileFormat.svg },
    { icon: 'terraform', extensions: ['tfstate'], languages: [languages.terraform], format: FileFormat.svg },
    { icon: 'test', extensions: ['tst'], format: FileFormat.svg },
    { icon: 'testjs', extensions: ['test.js', 'spec.js', 'test.jsx', 'spec.jsx'], light: true, format: FileFormat.svg },
    { icon: 'testts', extensions: ['test.ts', 'test.tsx', 'spec.ts', 'spec.tsx'], format: FileFormat.svg },
    { icon: 'tex', extensions: ['texi'], languages: [languages.tex, languages.latex], light: true, format: FileFormat.svg },
    { icon: 'text', extensions: ['csv'], languages: [languages.plaintext], format: FileFormat.svg },
    { icon: 'textile', extensions: [], languages: [languages.textile], format: FileFormat.svg },
    { icon: 'tfs', extensions: ['.tfignore'], filename: true, format: FileFormat.svg },
    { icon: 'todo', extensions: ['todo'], light: true, format: FileFormat.svg },
    { icon: 'toml', extensions: [], languages: [languages.toml], format: FileFormat.svg },
    { icon: 'travis', extensions: ['.travis.yml'], filename: true, format: FileFormat.svg },
    { icon: 'tsconfig', extensions: ['tsconfig.json', 'tsconfig.app.json', 'tsconfig.spec.json', 'tsconfig.e2e.json'], filename: true, format: FileFormat.svg },
    { icon: 'tslint', extensions: ['tslint.json'], filename: true, format: FileFormat.svg },
    { icon: 'twig', extensions: [], languages: [languages.twig], format: FileFormat.svg },
    { icon: 'typescript', extensions: [], languages: [languages.typescript], format: FileFormat.svg },
    { icon: 'typescript_official', extensions: [], languages: [languages.typescript], format: FileFormat.svg, disabled: true },
    { icon: 'typescriptdef', extensions: ['d.ts'], format: FileFormat.svg },
    { icon: 'typescriptdef_official', extensions: ['d.ts'], format: FileFormat.svg, disabled: true },
    { icon: 'vagrant', extensions: ['vagrantfile'], filename: true, format: FileFormat.svg },
    { icon: 'vash', extensions: ['vash'], light: true, format: FileFormat.svg },
    { icon: 'vb', extensions: [], languages: [languages.vb], format: FileFormat.svg },
    { icon: 'vbhtml', extensions: ['vbhtml'], format: FileFormat.svg },
    { icon: 'vbproj', extensions: ['vbproj'], format: FileFormat.svg },
    { icon: 'vcxproj', extensions: ['vcxproj'], format: FileFormat.svg },
    { icon: 'vhdl', extensions: [], languages: [languages.vhdl], format: FileFormat.svg },
    { // https://en.wikipedia.org/wiki/Video_file_format
      icon: 'video',
      extensions: ['3g2', '3gp', 'asf', 'amv', 'avi', 'divx', 'qt', 'f4a', 'f4b', 'f4p', 'f4v', 'flv',
        'm2v', 'm4v', 'mkv', 'mk3d', 'mov', 'mp2', 'mp4', 'mpe', 'mpeg', 'mpeg2', 'mpg', 'mpv', 'nsv',
        'ogv', 'rm', 'rmvb', 'svi', 'vob', 'webm', 'wmv'],
      format: FileFormat.svg,
    },
    { icon: 'view', extensions: [], format: FileFormat.svg },
    { icon: 'vim', extensions: ['.vimrc', '.gvimrc'], filename: true, languages: [languages.viml], format: FileFormat.svg },
    { icon: 'volt', extensions: [], languages: [languages.volt], format: FileFormat.svg },
    {
      icon: 'vscode',
      extensions: [
        'vscodeignore.json',
        'launch.json',
        'tasks.json',
        '.vscodeignore',
      ],
      filename: true,
      format: FileFormat.svg,
    },
    { icon: 'vsix', extensions: ['vsix'], light: true, format: FileFormat.svg },
    { icon: 'vue', extensions: [], languages: [languages.vue], format: FileFormat.svg },
    { icon: 'watchmanconfig', extensions: ['.watchmanconfig'], filename: true, format: FileFormat.svg },
    {
      icon: 'webpack',
      extensions: [
        'webpack.base.conf.coffee',
        'webpack.base.conf.js',
        'webpack.base.conf.ts',
        'webpack.common.coffee',
        'webpack.common.js',
        'webpack.common.ts',
        'webpack.config.coffee',
        'webpack.config.base.coffee',
        'webpack.config.common.coffee',
        'webpack.config.dev.coffee',
        'webpack.config.development.coffee',
        'webpack.config.staging.coffee',
        'webpack.config.test.coffee',
        'webpack.config.prod.coffee',
        'webpack.config.production.coffee',
        'webpack.config.js',
        'webpack.config.base.js',
        'webpack.config.common.js',
        'webpack.config.dev.js',
        'webpack.config.development.js',
        'webpack.config.staging.js',
        'webpack.config.test.js',
        'webpack.config.prod.js',
        'webpack.config.production.js',
        'webpack.config.ts',
        'webpack.config.base.ts',
        'webpack.config.common.ts',
        'webpack.config.dev.ts',
        'webpack.config.development.ts',
        'webpack.config.staging.ts',
        'webpack.config.test.ts',
        'webpack.config.prod.ts',
        'webpack.config.production.ts',
        'webpack.config.babel.js',
        'webpack.config.base.babel.js',
        'webpack.config.common.babel.js',
        'webpack.config.dev.babel.js',
        'webpack.config.development.babel.js',
        'webpack.config.staging.babel.js',
        'webpack.config.test.babel.js',
        'webpack.config.prod.babel.js',
        'webpack.config.production.babel.js',
        'webpack.dev.coffee',
        'webpack.dev.js',
        'webpack.dev.ts',
        'webpack.dev.conf.coffee',
        'webpack.dev.conf.js',
        'webpack.dev.conf.ts',
        'webpack.prod.coffee',
        'webpack.prod.js',
        'webpack.prod.ts',
        'webpack.prod.conf.coffee',
        'webpack.prod.conf.js',
        'webpack.prod.conf.ts',
        'webpack.mix.coffee',
        'webpack.mix.js',
        'webpack.mix.ts',
        'webpack.test.conf.coffee',
        'webpack.test.conf.js',
        'webpack.test.conf.ts',
      ],
      filename: true,
      format: FileFormat.svg,
    },
    { icon: 'wercker', extensions: ['wercker.yml'], filename: true, format: FileFormat.svg },
    { icon: 'word', extensions: ['doc', 'docx', 'docm', 'dot', 'dotx', 'dotm', 'wll'], format: FileFormat.svg },
    { icon: 'wxml', extensions: ['wxml'], format: FileFormat.svg },
    { icon: 'wxss', extensions: ['wxss'], format: FileFormat.svg },
    { icon: 'xcode', extensions: ['xcodeproj'], format: FileFormat.svg },
    { icon: 'xib', extensions: ['xib'], format: FileFormat.svg },
    { icon: 'xliff', extensions: ['xliff', 'xlf'], format: FileFormat.svg },
    { icon: 'xml', extensions: ['pex', 'tmlanguage'], languages: [languages.xml], format: FileFormat.svg },
    { icon: 'xsl', extensions: [], languages: [languages.xsl], format: FileFormat.svg },
    { icon: 'yaml', extensions: ['yml'], light: true, languages: [languages.yaml, languages.textmateyaml], format: FileFormat.svg },
    { icon: 'yang', extensions: [], languages: [languages.yang], format: FileFormat.svg },
    { icon: 'yarn', extensions: ['yarn.lock', '.yarnrc', '.yarnclean', '.yarn-integrity', '.yarn-metadata.json', '.yarnignore'], filename: true, format: FileFormat.svg },
    { icon: 'yeoman', extensions: ['.yo-rc.json'], filename: true, format: FileFormat.svg },
    { icon: 'zip', extensions: ['zip', 'rar', '7z', 'tar', 'gz', 'bzip2', 'xz', 'bz2'], format: FileFormat.svg },
    { icon: 'zip2', extensions: ['zip', 'rar', '7z', 'tar', 'gz', 'bzip2', 'xz', 'bz2'], format: FileFormat.svg, disabled: true },
  ],
};


================================================
FILE: misc/init-demo.sh
================================================
#!/bin/bash

rm -rf ~/demo
mkdir -p ~/demo/mybooklive/Tv.Show

for i in {1..5}; do
	folder=~/demo/downloads/Tv.Show.S01E0$i
	mkdir -p $folder
	touch $folder/Tv.Show.S01E0$i.{mkv,srt,nfo}
done


================================================
FILE: misc/link-all.sh
================================================
#!/bin/bash
npm link jumpfm-clock jumpfm-copy jumpfm-fs jumpfm-gist jumpfm-git-status jumpfm-history jumpfm-jump jumpfm-version jumpfm-weather jumpfm-zip jumpfm-file-ops jumpfm-key-nav jumpfm-flat-mode 


================================================
FILE: misc/modd.conf
================================================
icons.awk {
	prep: ./icons.awk icons.txt 
}


================================================
FILE: misc/omg-ubunut.txt
================================================
Hi Joey,

I'm the developer of JumpFm (http://jumpfm.org).
Its an Electron based (I know, I know.. but its really not that bad) file manager inspired by fman (http://bit.ly/2x70Q39) and exa (https://the.exa.website/).

It comes with some cool features like jumping, git status integration and more (see http://jumpfm.org for more details).

It is a completely open source project, and it is extremely easy (as easy as writing NPM package) to extend its functionality via its plug-in system. 

It can be downloaded from github as an AppImage (https://github.com/Gilad-Kutiel-App/jumpfm/releases).

I also made some short videos (http://bit.ly/2wljs2L).

Best,
Gilad Kutiel



================================================
FILE: misc/reddit.txt
================================================
tl;dr
I made JumpFm (http://bit.ly/2uBFWIC), need your feedback

Hi,

I decided to format my machine last weekend. 
Then, after reinstalling almost everything, I was about to reinstall double commander.
Basically, I like double commander but it takes me a lot of configuration to bring it to a state that I can work with it.
I also came across fman (http://bit.ly/2uBwIw6) couple of weeks ago, and it seems really great but it is not an open source and requires a subscription fee.
Also, I haven't done any programming for quite a while and wanted to refresh my memory a bit.
For all the above reasons I decided to start a new side project and create my own file manager - JumpFm (http://bit.ly/2uBFWIC).
It is currently in a very early stage but there is already a working version. It was only tested on my machine but it seems to do what is suppose to do.
I'm planning to keep working on this project and would really appreciate your feedback:
- Which FM are you using ?
- What features do you like/need/must ?
- Feedback about the site/help/etc...
- Bugs

Thank you very much,
Gilad


================================================
FILE: package.json
================================================
{
    "name": "jumpfm",
    "version": "1.0.6",
    "description": "A file manager that lets you jump",
    "author": {
        "name": "Gilad Kutiel",
        "email": "gilad.kutiel@gmail.com"
    },
    "license": "ISC",
    "dependencies": {
        "check-dependencies": "^1.1.0",
        "electron-simple-updater": "^1.2.1",
        "filesize": "^3.5.10",
        "fs-extra": "^4.0.1",
        "homedir": "^0.6.0",
        "moment": "^2.18.1",
        "node-cmd": "^3.0.0",
        "node-watch": "^0.5.5",
        "node.os": "^1.2.4",
        "npm": "^6.2.0"
    },
    "devDependencies": {
        "@types/electron": "^1.6.10",
        "@types/fs-extra": "^4.0.8",
        "@types/keyboardjs": "^2.2.31",
        "@types/node": "^8.10.21",
        "@types/npm": "^2.0.29",
        "@types/watch": "^1.0.0",
        "electron-builder": "^19.56.2",
        "jumpfm-api": "^1.1.4"
    },
    "optionalDependencies": {
        "7zip-bin-win": "^2.1.0"
    },
    "homepage": "https://jumpfm.org",
    "repository": {
        "type": "git",
        "url": "git+https://github.com/Gilad-Kutiel-App/jumpfm.git"
    },
    "bugs": {
        "url": "https://github.com/Gilad-Kutiel-App/jumpfm/issues"
    },
    "main": "app.js",
    "build": {
        "appId": "com.github.gkutiel.jumpfm",
        "compression": "maximum",
        "electronVersion": "1.7.5",
        "linux": {
            "files": [
                "**/*",
                "build/icons/*"
            ],
            "target": [
                "AppImage"
            ],
            "category": "Utility",
            "publish": "github"
        },
        "win": {
            "target": "nsis"
        }
    },
    "scripts": {
        "test": "mocha js",
        "pack": "build --dir",
        "dist": "build",
        "publish": "build --publish always",
        "postinstall": "electron-builder install-app-deps"
    }
}


================================================
FILE: scss/_app.scss
================================================
@import 'colors';
@font-face {
    font-family: DroidSansMono;
    src: url('../fonts/DroidSansMono.ttf');
}

* {
    font-family: 'DroidSansMono';
    box-sizing: border-box;
}

html,
body {
    height: 100%;
    width: 100%;
    padding: 0;
    margin: 0;
}

#app {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    flex-direction: column;
}

html,
body,
table,
input {
    background-color: $color-bg;
    color: $color-fg;
}

input {
    font-size: inherit;
    padding: .2em;
    outline: none;
    border: none;
    background-color: $color-bg;
}

================================================
FILE: scss/_classes.scss
================================================
@import 'colors';
.border {
  border: 1px solid $color-natural;
}

.txt-no-wrap {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

 ::-webkit-scrollbar {
  display: none;
}

.file-icon {
  width: 1em;
  height: 1em;
}

================================================
FILE: scss/_colors.scss
================================================
$color-border:#646464;
$color-err:#F58E8E;
$color-natural:#A9D3AB;
$color-warn:#FED37E;
$color-info:#7AABD4;
$color-06:#D6ADD5;
$color-07:#79D4D5;
$color-08:#D4D4D4;
$color-bg:lighten(#2D2D2D, 5%);
$color-fg:#D4D4D4;

================================================
FILE: scss/_dialog.scss
================================================
@import 'colors';
@import 'classes';
#dialog {
  display: none;
  position: absolute;
  top: 20%;
  left: 0;
  right: 0;
  width: 600px;
  margin: 0 auto;
  background-color: transparent;
}

#dialog-label,
#dialog-input {
  padding: .8em;
}

#dialog-label,
#dialog-input,
#dialog-sug {
  @extend .border;
  background-color: $color-bg;
}

#dialog-input,
#dialog-sug {
  width: 100%;
}

#dialog-content {
  display: flex;
  #dialog-label {
    color: $color-info;
    font-weight: bold;
    border-right: none;
  }
}

#dialog-left {
  flex-grow: 0;
  flex-shrink: 0;
}

#dialog-right {
  flex-grow: 1;
  overflow: hidden;
  #dialog-input {
    border-left: none;
    padding-left: 0;
  }
  #dialog-sug {
    border-top: none;
    line-height: 1.5;
    padding: 0;
    list-style-type: none;
    margin: 0;
    [cur] {
      background-color: $color-border;
    }
    b {
      color: $color-info;
    }
    li {
      @extend .txt-no-wrap;
      padding: 0 .2em;
    }
  }
}

================================================
FILE: scss/_panel.scss
================================================
@import 'colors';
@import 'classes';
.panel {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  width: 50%;
  border: 0 solid $color-border;
  &:first-child {
    border-right-width: 2px
  }
  &:nth-child(2) {
    border-left-width: 2px
  }
}

.panel>title {
  @extend .txt-no-wrap;
  flex-shrink: 0;
  display: block;
  width: 100%;
}

.panel[active]>title {
  background-color: darken($color-info, 20%);
  font-weight: bold;
}

.panel tr[hidden] {
  display: none;
}

.panel tr[cur] {
  background-color: $color-border;
  font-weight: bold;
}

.panel[active] tr[selected] {
  background-color: darken($color-warn, 55%);
}

.panel[active] tr[cur] {
  background-color: darken($color-warn, 45%);
}

table {
  width: 100%;
  display: flex;
  flex-direction: column;
  table-layout: fixed;
  flex-grow: 1;
  border-collapse: collapse;
  text-align: left;
}

thead {
  background-image: linear-gradient($color-border, $color-bg);
}

tbody {
  display: block;
  overflow-y: auto;
  flex-grow: 1;
}

thead,
tbody tr {
  display: table;
  width: 100%;
  table-layout: fixed;
}

th:first-child,
td:first-child {
  width: 1.5em;
}

th:nth-child(3),
td:nth-child(3) {
  width: 6em;
}

th:nth-child(4),
td:nth-child(4) {
  width: 10.5em;
}

th,
td {
  @extend .txt-no-wrap;
  padding: .1em .2em;
  &:first-child {
    padding-left: .5em;
    padding-right: 1.5em;
  }
  &:last-child {
    padding-right: .5em;
  }
}

.filter {
  border-top: 1px solid $color-border;
}

================================================
FILE: scss/_panels.scss
================================================
#panels {
    flex-grow: 1;
    display: flex;
    flex-direction: row;
}

================================================
FILE: scss/_statusbar.scss
================================================
@import 'colors';
// 
#statusbar {
    display: flex;
    flex-shrink: 0;
    padding: .1em 0;
    border-top: 3px solid $color-border;
}

#statusbar-msgs {
    display: flex;
    flex-grow: 1;
    align-items: center;
    font-size: 90%;
    padding-right: 1em;
    overflow: hidden;
    .msg {
        cursor: default;
        flex-shrink: 0;
        border-right: 1px solid $color-border;
        padding: 0 .5em;
        &:last-child {
            border-right: none;
        }
        &:empty {
            padding: 0;
        }
    }
}

#statusbar-buttons {
    display: flex;
    flex-direction: row-reverse;
    flex-shrink: 0;
    font-size: 120%;
    .btn {
        padding-right: .5em;
    }
}

.btn {
    font-size: 1em;
    display: inline-block;
    cursor: pointer;
    padding: 0;
    margin: 0;
    color: $color-natural;
    border: none;
    outline: none;
    opacity: .5;
    text-decoration: none;
    &:hover {
        opacity: 1;
    }
}

[type=info],
[type=info][data-title]:before {
    color: $color-info;
}

[type=warn],
[type=warn][data-title]:before {
    color: $color-warn;
}

[type=err],
[type=err][data-title]:before {
    color: $color-err;
}

================================================
FILE: scss/_tooltip.scss
================================================
@import 'colors';
[data-title] {
    &:before {
        position: absolute;
        content: attr(data-title);
        white-space: nowrap;
        color: $color-fg;
        background-color: $color-bg;
        width: auto;
        padding: .5em;
        border: 1px solid $color-border;
        border-radius: 3px;
        transform: translate(1em, -3.5em);
        opacity: 0;
        visibility: hidden;
    }
    &:hover:before {
        visibility: visible;
        transition: all .2s;
        opacity: 1;
        height: auto;
    }
}

#statusbar-buttons {
    [data-title] {
        &:before {
            font-size: 80%;
            transform: translate(-3em, -3em);
        }
        &:hover:before {}
    }
}

================================================
FILE: scss/index.scss
================================================
@import 'app';
@import 'panels';
@import 'panel';
@import 'classes';
@import 'dialog';
@import 'statusbar';
@import 'tooltip';

================================================
FILE: ts/Dialog.ts
================================================
import { Dialog as DialogApi, DialogSpec, Suggestion } from 'jumpfm-api'
import { shortway } from "./shortway";

interface SuggestionLi extends Suggestion {
    li: HTMLLIElement
}

export class Dialog implements DialogApi {
    private readonly divDialog: HTMLDivElement =
    document.getElementById('dialog') as HTMLDivElement

    private readonly divLabel: HTMLDivElement =
    document.getElementById('dialog-label') as HTMLDivElement

    private readonly input: HTMLInputElement =
    document.getElementById('dialog-input') as HTMLInputElement

    private readonly olSug: HTMLOListElement =
    document.getElementById('dialog-sug') as HTMLOListElement

    private suggestions: SuggestionLi[] = []

    private onAccept = (val: string, sug: Suggestion) => { }
    private suggest = val => []
    private cur: number

    constructor() {
        const on = (type, action, capture = false) =>
            this.input.addEventListener(type, action, capture)

        on('keydown', e => {
            e.stopPropagation()
        })
        on('blur', this.close)
        on('keydown', shortway('esc', this.close))
        on('keydown', shortway('enter', () => {
            this.close()
            this.onAccept(
                this.input.value,
                this.suggestions[this.cur]
            )
        }))


        on('keydown', shortway('down', () =>
            this.setCur(this.cur + 1)
        ))

        on('keydown', shortway('up', () =>
            this.setCur(this.cur - 1)
        ))

        on('input', this.updateSuggestions)
    }

    private updateSuggestions = () => {
        this.suggestions =
            this.suggest(this.input.value)
                .map(sug => {
                    const li = document.createElement('li')
                    li.innerHTML = sug.html
                    sug.li = li
                    return sug
                })
        this.clearSuggestions()
        this.suggestions.forEach(sug => {
            this.olSug.appendChild(sug.li)
        })
        const curSuggestion = this.suggestions[this.cur = 0]
        if (curSuggestion) curSuggestion.li.setAttribute('cur', '')
    }

    private setCur = (i: number) => {
        if (!this.suggestions.length) return
        const curSug = this.suggestions[this.cur]
        if (curSug) curSug.li.removeAttribute('cur')
        this.cur = Math.max(0, Math.min(i, this.suggestions.length - 1))
        this.suggestions[this.cur].li.setAttribute('cur', '')
    }

    private clearSuggestions = () => {
        while (this.olSug.lastChild) this.olSug.removeChild(this.olSug.lastChild)
    }


    private close = () => {
        this.divDialog.style.display = 'none'
    }

    open = (spec: DialogSpec) => {
        this.suggestions = []
        this.clearSuggestions()
        this.divLabel.textContent = spec.label
        this.cur = 0

        this.divDialog.style.display = 'block'
        this.input.value = ''
        this.input.select()

        spec.onOpen && spec.onOpen(this.input)
        this.suggest = spec.suggest || (val => [])
        this.onAccept = spec.onAccept
    }
}

================================================
FILE: ts/Filter.ts
================================================
import { FilterBox as FilterApi } from 'jumpfm-api'
import { getKeys } from "./files";
import { shortway } from "./shortway";

export class Filter implements FilterApi {
    readonly input: HTMLInputElement = document.createElement('input')

    private readonly handlers: ((val: string) => void)[] = []


    constructor() {
        this.input.className = 'filter'
        this.input.addEventListener('keydown', e => e.stopPropagation(), false)
        this.input.addEventListener('input', () => {
            this.notifyAll()
        }, false)

        this.input.addEventListener('blur', this.hide, false)
        this.hide()
    }

    private notifyAll(): any {
        this.handlers.forEach(handler => {
            handler(this.input.value)
        });
    }

    set = (val: string) => {
        this.input.value = val
        this.notifyAll()
    }

    get = () => {
        return this.input.value
    }

    onChange = (handler: (val: string) => void) => this.handlers.push(handler)

    focus = () => {
        this.input.style.display = 'block'
        this.input.focus()
    }

    hide = () => this.input.style.display = 'none'

    bind = (actionName: string, defaultKeys: string[], action: () => void) => {
        getKeys(actionName, defaultKeys).forEach(combo => {
            const cb = shortway(combo, (e) => {
                e.preventDefault()
                action()
            })
            this.input.addEventListener('keydown', cb, false)
        })
    }
}

================================================
FILE: ts/Item.ts
================================================
import { Item as ItemApi, File } from 'jumpfm-api'

import * as moment from 'moment'
import * as fileSize from 'filesize'

type attr = 'cur' | 'hidden' | 'selected'

export class Item implements ItemApi {
    private hidden: boolean = false
    private selected: boolean = false

    private readonly icon = document.createElement('img')

    private readonly tdIcon = document.createElement('td')
    private readonly tdName = document.createElement('td')
    private readonly tdSize = document.createElement('td')
    private readonly tdTime = document.createElement('td')

    readonly tr = document.createElement('tr')

    constructor(item: File) {
        this.icon.className = 'file-icon'
        this.tdIcon.appendChild(this.icon)

        this.tr.appendChild(this.tdIcon)
        this.tr.appendChild(this.tdName)
        this.tr.appendChild(this.tdSize)
        this.tr.appendChild(this.tdTime)

        this.path = item.path
        this.name = item.name

        this.tdName.textContent =
            item.name || '--'
    }

    readonly path: string;
    readonly name: string;

    private readonly attrs: { [attr: string]: boolean } = {}

    private set = (attr: attr) => (b: boolean) => {
        this.attrs[attr] = b
        if (b)
            this.tr.setAttribute(attr, '')
        else
            this.tr.removeAttribute(attr)
        return this
    }

    private is = (attr: attr) => this.attrs[attr]

    setCur: (b: boolean) => void = this.set('cur')
    setHidden: (b: boolean) => void = this.set('hidden')
    setSelected: (b: boolean) => void = this.set('selected')

    hide = () => this.setHidden(true)
    show = () => this.setHidden(false)

    isSelected = () => this.is('selected')
    isHidden = () => this.is('hidden')

    setAttribute(name: string, val: string = '') {
        this.tr.setAttribute(name, val)
        return this
    }

    setIcon = (src: string) => {
        this.icon.src = src
        return this
    }

    setTime = (time: number) => {
        this.tdTime.textContent =
            (time && moment(time).format('DD/MM/YYYY hh:mm') || '--')
        return this
    }

    setSize = (size: number) => {
        this.tdSize.textContent =
            (size && fileSize(size) || '--')
        return this
    }
}

================================================
FILE: ts/JumpFm.ts
================================================
import { } from 'electron'
import { JumpFm as JumpFmApi } from 'jumpfm-api'
import { Panel } from "./Panel"
import { StatusBar } from "./StatusBar"
import { PluginManager } from "./PluginManager";
import { Dialog } from "./Dialog";
import { shortway } from "./shortway";
import { Settings } from "./Settings";
import {
    getKeys
    , saveKeyboard
    , root
    , packageJson
    , keyboardPath
    , settingsPath
    , pluginsPackageJson
} from "./files";

import * as homedir from 'homedir'
import * as fs from 'fs'
import * as watch from 'node-watch'

export class JumpFm implements JumpFmApi {
    private active: 0 | 1 = 0
    private readonly divPanels = document.getElementById('panels')
    private readonly pluginManager = new PluginManager(this)
    private readonly watchers: { [name: string]: fs.FSWatcher } = {}

    readonly package = packageJson
    readonly root = root
    readonly settings = new Settings()
    readonly dialog = new Dialog()
    readonly electron: Electron.AllElectron = require('electron')
    readonly panels: Panel[] = [new Panel(), new Panel()]
    readonly statusBar: StatusBar = new StatusBar()
    readonly argv: string[]

    private passive = (): 0 | 1 => (this.active + 1) % 2 as 0 | 1

    private setActive = (i: 0 | 1) => {
        this.active = i
        this.panels[this.active].setActive(true)
        this.panels[this.passive()].setActive(false)
    }

    watchStart = (name, path, then, recursive = false) => {
        this.watchStop(name)
        console.log('WATCH START', name, path)
        setImmediate(() => {
            let to
            this.watchers[name] = watch(path, { recursive: recursive }, () => {
                clearTimeout(to)
                to = setTimeout(then, 10)
            })
        })
    }

    watchStop = (name: string) => {
        if (this.watchers[name]) {
            console.log('WATCH STOP', name)
            this.watchers[name].close()
        }
    }

    getPanelActive = () =>
        this.panels[this.active]

    getPanelPassive = () =>
        this.panels[this.passive()]

    panelsSwap = () => {
        this.active = this.passive()
        const tmp = this.panels[0]
        this.panels[0] = this.panels[1]
        this.panels[1] = tmp
        this.divPanels.insertBefore(this.panels[0].divPanel, this.panels[1].divPanel)
    }

    panelsSwitch = () =>
        this.setActive(this.passive())

    bind = (actionName: string, defaultKeys: string[], action: () => void) => {
        getKeys(actionName, defaultKeys).forEach(combo => {
            const cb = shortway(combo, (e) => {
                e.preventDefault()
                action()
            })
            document.addEventListener('keydown', cb, false)
        })
    }

    constructor(argv: string[]) {
        this.argv = argv
        this.panels.forEach(panel => {
            this.divPanels.appendChild(panel.divPanel)
        })

        const opn = (url) => () => this.electron.shell.openItem(url)
        this.statusBar.buttonAdd('fa-info', 'About', opn('http://jumpfm.org'))
        this.statusBar.buttonAdd('fa-key', 'Keyboard', opn(keyboardPath))
        this.statusBar.buttonAdd('fa-gear', 'Settings', opn(settingsPath))
        this.statusBar.buttonAdd('fa-plug', 'Plugins', opn(pluginsPackageJson))

        this.pluginManager.loadAndUpdatePlugins(() => {
            saveKeyboard()
            this.panels.forEach(panel => panel.cd(homedir()))
            this.setActive(0)
        })
    }
}

================================================
FILE: ts/Panel.ts
================================================
import { Panel as PanelApi, Url, File } from 'jumpfm-api'

import { Item } from './Item'
import { Filter } from './Filter'
import { getKeys } from "./files";
import { shortway } from "./shortway";

export class Panel implements PanelApi {
    private readonly table: HTMLTableElement = document.createElement('table')
    private readonly tbody: HTMLTableSectionElement = document.createElement('tbody')
    private readonly thead: HTMLTableSectionElement = document.createElement('thead')
    private readonly title: HTMLTitleElement = document.createElement('title')
    private readonly trHead: HTMLTableRowElement = document.createElement('tr')

    readonly divPanel: HTMLDivElement = document.createElement('div')
    readonly filterBox: Filter = new Filter()

    private readonly filters: { [name: string]: ((item: Item) => boolean) } = {}
    private readonly onCds: (() => void)[] = []
    private readonly onItemsAddeds: ((newItems: Item[]) => void)[] = []
    private readonly onLoads: (() => void)[] = []

    private active = false
    private url: Url
    private cur: number = 0
    private items: Item[] = []
    private visibleItems: Item[] = []

    constructor() {
        ['', 'Name', 'Size', 'Time'].forEach(head => {
            const td = document.createElement('td')
            td.textContent = head
            this.trHead.appendChild(td)
        })

        this.divPanel.className = 'panel'
        this.divPanel.appendChild(this.title)
        this.divPanel.appendChild(this.table)
        this.thead.appendChild(this.trHead)
        this.table.appendChild(this.thead)
        this.table.appendChild(this.tbody)
        this.divPanel.appendChild(this.filterBox.input)

        this.filterBox.onChange(this.setTitle)
    }

    private clearItems = () => {
        while (this.tbody.lastChild) this.tbody.removeChild(this.tbody.lastChild)
    }

    private addItems = (items: Item[]) => {
        items.forEach(item => this.tbody.appendChild(item.tr))
    }

    private setTitle = () => {
        const filter = this.filterBox.get()
        const protocol = this.url.protocol
        this.title.textContent =
            (protocol ? protocol + ':' : '')
            + this.url.path
            + (filter ? ' [' + filter + ']' : '')
    }

    private scrollToCur = () => {
        const curItem = this.getCurrentItem()
        if (!curItem) return
        const tr = curItem.tr
        const trRect = tr.getBoundingClientRect()
        const tbodyRect = this.tbody.getBoundingClientRect()
        if (trRect.bottom > tbodyRect.bottom)
            tr.scrollIntoView(false)
        if (trRect.top < tbodyRect.top)
            tr.scrollIntoView(true)
    }

    private safeUpdateCurrent = (b: boolean) => {
        const item = this.getCurrentItem()
        if (item) item.setCur(b)
    }

    private setCur = (i) => {
        this.safeUpdateCurrent(false)
        this.cur = Math.max(0, Math.min(i, this.visibleItems.length - 1))
        this.safeUpdateCurrent(true)
    }

    private progressiveProcessItems =
    (process: (items: Item[]) => void) =>
        (from: number, done?: () => void) => {

            if (from > this.items.length) return done && done()
            const to = from + 100

            process(this.items.slice(from, to))

            setImmediate(() => {
                this.progressiveProcessItems(process)(to, done)
            })
        }

    private progressiveAddItems = this.progressiveProcessItems(items => {
        this.addItems(items)

        this.onItemsAddeds.forEach(f =>
            setImmediate(() => f(items))
        )
    })

    private progressiveUpdateVisibility = this.progressiveProcessItems(items => {
        items.forEach(item => {
            const visible =
                Object.values(this.filters)
                    .every(filter => filter(item))

            if (visible) {
                this.visibleItems.push(item)
                item.show()
            } else {
                item.hide()
            }
        })
    })


    private updateVisibility = () => {
        console.log('updateVisibility')
        this.safeUpdateCurrent(false)
        this.visibleItems = []
        this.progressiveUpdateVisibility(0, () => {
            console.log('progressiveUpdateVisibility')
            this.setCur(this.cur)
            this.scrollToCur()
        })
    }

    private selectRange = (from: number, to: number) => {
        if (from > to) return this.selectRange(to, from)
        for (let i = from
            ; i <= Math.min(to, this.visibleItems.length - 1)
            ; i++
        ) {
            const item = this.visibleItems[i]
            if (item) item.setSelected(true)
        }
    }

    private rowsInView = () => {
        return Math.floor(this.tbody.clientHeight / this.visibleItems[0].tr.scrollHeight)
    }

    private stepTo = (i, select: boolean = false) => {
        if (select) this.selectRange(this.cur, i)
        this.setCur(i)
        this.scrollToCur()
    }

    setActive = (b: boolean) => {
        this.active = b
        if (b)
            this.divPanel.setAttribute('active', '')
        else
            this.divPanel.removeAttribute('active')
    }

    cd(path: string): void;
    cd(url: Url): void;
    cd(pathOrUrl: any) {
        if (typeof pathOrUrl == 'string') return this.cd({
            protocol: '',
            path: pathOrUrl,
            query: {}
        })

        this.url = pathOrUrl as Url
        console.log('cd', this.url)
        this.setTitle()
        this.onCds.forEach(f => setImmediate(f))
    }

    onCd = (then: () => void) =>
        this.onCds.push(then)

    onItemsAdded = (then: (newItems: Item[]) => void) =>
        this.onItemsAddeds.push(then)

    onLoad = (then: () => void) => {
        this.onLoads.push(then)
    }

    step = (d: number, select?: boolean) => {
        const newCur
            = d < 0
                ? Math.max(0, this.cur + d)
                : Math.min(this.cur + d, this.visibleItems.length - 1)

        this.stepTo(newCur, select)
    }

    stepPgUp = (select?: boolean) => {
        this.step(-this.rowsInView(), select)
    }

    stepPgDown = (select?: boolean) => {
        this.step(this.rowsInView(), select)
    }

    stepStart = (select?: boolean) => {
        this.stepTo(0, select)
    }

    stepEnd = (select?: boolean) => {
        this.stepTo(this.visibleItems.length - 1, select)
    }

    selectNone = () =>
        this.items.forEach(item => item.setSelected(false))

    selectAll = () =>
        this.items.forEach(item => item.setSelected(true))

    selectToggleCurrent = () => {
        const item = this.getCurrentItem()
        item.setSelected(!item.isSelected())
    }

    getUrl = () =>
        this.url

    getItems = () =>
        this.items

    getSelectedItems = () =>
        this.visibleItems.filter((item, i) =>
            i === this.cur || item.isSelected()
        )

    getCurrentItem = () =>
        this.visibleItems[this.cur]

    setItems = (items: File[]) => {
        console.log('setItems')
        this.items = items.map(item => new Item(item))

        this.clearItems()
        this.progressiveAddItems(0, () => {
            this.onLoads.forEach(onLoad => {
                setImmediate(onLoad)
            })
        })
        this.updateVisibility()
        return this
    }

    filterSet = (name: string, filter: (item: Item) => boolean) => {
        console.log('filterSet', filter)
        this.filters[name] = filter
        this.updateVisibility()
    }

    filterRemove = (name: string) => {
        delete this.filters[name]
        this.updateVisibility()
    }

    bind = (actionName: string, defaultKeys: string[], action: () => void) => {
        getKeys(actionName, defaultKeys).forEach(combo => {
            const cb = shortway(combo, (e) => {
                if (!this.active) return
                e.preventDefault()
                action()
            })
            document.addEventListener('keydown', cb, false)
        })
    }
}

================================================
FILE: ts/PluginManager.ts
================================================
import { JumpFm } from 'jumpfm-api'

import {
    pluginsPath,
    pluginsPackageJson,
    packageJson,
    savePlugins
} from './files';

import * as check from 'check-dependencies'
import * as fs from 'fs-extra'
import * as npm from 'npm'
import * as path from 'path'
import * as watch from 'node-watch'

interface checkRes {
    status: number,         // 0 if successful, 1 otherwise 
    depsWereOk: boolean,    // true if dependencies were already satisfied 
    log: string[],          // array of logged messages 
    error: string[],        // array of logged errors 
}

const defaultPlugins = {
    dependencies: {
        "jumpfm-font-size": "latest",
        "jumpfm-clock": "latest",
        "jumpfm-copy": "latest",
        "jumpfm-file-ops": "latest",
        "jumpfm-filter": "latest",
        "jumpfm-flat-mode": "latest",
        "jumpfm-fs": "latest",
        "jumpfm-gist": "latest",
        "jumpfm-git-status": "latest",
        "jumpfm-history": "latest",
        "jumpfm-icons": "latest",
        "jumpfm-jump": "latest",
        "jumpfm-key-nav": "latest",
        "jumpfm-version": "latest",
        "jumpfm-weather": "latest",
        "jumpfm-zip": "latest"
    }
}

class PluginsLoader {
    jumpFm: JumpFm;
    done: (err?: any) => void;
    private loaded = {}

    constructor(jumpFm: JumpFm, done: (err?) => void) {
        this.jumpFm = jumpFm
        this.done = () => {
            jumpFm.statusBar.msg('plugins').setText('')
            done()
        }
    }

    private loadCss = (href) => {
        if (!href) return
        const link = document.createElement('link')
        link.setAttribute('rel', 'stylesheet')
        link.setAttribute('href', href)
        document.head.appendChild(link)
    }

    private loadPlugin = (name: string) => {
        try {
            console.time(name)

            if (this.loaded[name]) return
            this.loaded[name] = true

            const pluginDir = path.join(pluginsPath, 'node_modules', name)
            const plugin = require(pluginDir)

            if (plugin.css)
                plugin.css.forEach(css =>
                    this.loadCss(path.join(pluginDir, css))
                )

            plugin.load(this.jumpFm)

            console.timeEnd(name)
        } catch (e) {
            console.log(e)
        }
    }

    private getPackage = () => {
        try {
            return fs.readJsonSync(pluginsPackageJson)
        } catch (e) {
            fs.writeFileSync(
                pluginsPackageJson
                , JSON.stringify(defaultPlugins, null, 4)
            )
            return defaultPlugins
        }
    }

    loadPlugins(pkg) {
        try {
            Object.keys(pkg.dependencies).forEach(name => {
                this.loadPlugin(name)
            })
            this.done()
        } catch (e) {
            console.log(e)
            this.done(e)
        }
    }

    load() {
        const pkg = this.getPackage()
        const checkRes: checkRes = check.sync({
            packageDir: pluginsPath
        })
        if (checkRes.depsWereOk) {
            this.loadPlugins(pkg)
        }
        process.chdir(pluginsPath)
        npm.load({
            save: true
        }, (err, res) => {
            if (err) return this.done(err)
            npm.commands.update([], (err, res) => {
                if (err) return this.done(err)
                if (!checkRes.depsWereOk) this.loadPlugins(pkg)
            })
        })
    }
}

export class PluginManager {
    readonly jumpFm: JumpFm

    constructor(jumpFm) {
        this.jumpFm = jumpFm
    }

    loadAndUpdatePlugins = (done: (err?) => void) => {
        this.jumpFm.statusBar.msg('plugins')
            .setType('info')
            .setText('Downloading plugins (can take a while)...')
            .setTooltip('This might take some time')

        const pluginLoader = new PluginsLoader(this.jumpFm, done)

        pluginLoader.load()
        watch(pluginsPackageJson, () => {
            pluginLoader.load()
        })
    }
}

================================================
FILE: ts/Settings.ts
================================================
import { Settings as SettingsApi } from 'jumpfm-api'

import { settings, saveSettings } from './files'

type Type = 'string' | 'number'

export class Settings implements SettingsApi {
    private get = <T>(type: Type) => (key: string, defaultValue: T) => {
        const val = settings[key]
        if (val && (typeof val === type)) return val
        settings[key] = defaultValue
        saveSettings(settings)
        return defaultValue
    }

    getNum = this.get<number>('number')
    getStr = this.get<string>('string')
}

================================================
FILE: ts/StatusBar.ts
================================================
import { StatusBar as StatusBarApi, Msg as MsgAPi } from 'jumpfm-api'

class Msg implements MsgAPi {
    readonly divMsg: HTMLDivElement = document.createElement('div')

    constructor() {
        this.divMsg.className = 'msg'
    }

    setType = (type: "info" | "warn" | "err") => {
        this.divMsg.setAttribute('type', type)
        return this
    }

    setText = (txt: string) => {
        this.divMsg.textContent = txt
        return this
    }

    setTooltip = (txt: string) => {
        this.divMsg.setAttribute('data-title', txt)
        return this
    }

    setClearTimeout = (timeout: number) => {
        setTimeout(() => this.setText(''), timeout)
        return this
    }

    setAttr = (name: string, b: boolean) => {
        if (b)
            this.divMsg.setAttribute(name, '')
        else
            this.divMsg.removeAttribute(name)

        return this
    }
}

class Button {
    readonly a: HTMLAnchorElement = document.createElement('a')
    private readonly i = document.createElement('i')

    constructor(faIcon: string, tooltip: string) {
        this.a.className = 'btn'
        this.a.setAttribute('data-title', tooltip)
        this.a.target = 'about:blank'
        this.i.className = `fa ${faIcon}`
        this.a.appendChild(this.i)
    }
}

export class StatusBar implements StatusBarApi {
    private readonly divMsgs: HTMLDivElement = document
        .getElementById('statusbar-msgs') as HTMLDivElement

    private readonly divButtons: HTMLDivElement = document
        .getElementById('statusbar-buttons') as HTMLDivElement

    private readonly msgs: { [name: string]: Msg } = {}

    msg = (name: string): MsgAPi => {
        if (this.msgs[name]) return this.msgs[name]
        const msg = new Msg()
        this.msgs[name] = msg
        this.divMsgs.appendChild(msg.divMsg)
        return msg
    }

    clear = (name: string) => {
        const msg = this.msgs[name]
        if (!msg) return
        msg.setText('')
    }
    msgClear = this.clear

    buttonAdd(faIcon: string, tooltip: string, action: () => void) {
        const a = new Button(faIcon, tooltip).a
        this.divButtons.appendChild(a)
        a.addEventListener('click', action, false)
    }
}

================================================
FILE: ts/files.ts
================================================
import * as fs from 'fs-extra';
import * as homedir from 'homedir';
import * as path from 'path';

export interface Plugins {
    name: string
    version: string
    dependencies: { [name: string]: string }
}

const load = (path: string) => {
    try {
        return require(path)
    } catch (e) {
        console.log(e)
        return {}
    }
}

const save = <T>(path: string) => (obj: T) => {
    fs.writeFileSync(path, JSON.stringify(obj, null, 4))
    return obj;
}

export const packageJson = require('../package.json')

export const root = path.join(homedir(), ".jumpfm")
export const pluginsPath = path.join(root, 'plugins')
if (!fs.existsSync(pluginsPath))
    fs.mkdirpSync(pluginsPath)

export const pluginsPackageJson = path.join(pluginsPath, 'package.json')
export const settingsPath = path.join(root, 'settings.json')
export const keyboardPath = path.join(root, 'keyboard.json')

export const settings = load(settingsPath)
export const keyboard = load(keyboardPath)

export const saveSettings = save(settingsPath)
export const saveKeyboard = () => save(keyboardPath)(keyboard)
export const savePlugins = save<Plugins>(pluginsPackageJson)


export const getKeys = (actionName: string, defaultKeys: string[]): string[] => {
    const keys = keyboard[actionName]
    if (keys && Array.isArray(keys)) return keys
    keyboard[actionName] = defaultKeys
    return defaultKeys
}


================================================
FILE: ts/icons.ts
================================================

const icons = require('../icons.json')
const extensions = {}
for (var icon in icons) {
    icons[icon].forEach(ext => {
        extensions[ext] = icon
    });
}

export const getExtIcon = (ext: string) => {
    const icon = extensions[ext]
    if (icon) return 'file-icons/file_type_' + icon + '.svg'
}

================================================
FILE: ts/main.ts
================================================
document.addEventListener('DOMContentLoaded', () => {
    console.time('main')
    new (require('./js/JumpFm.js').JumpFm)(require('electron').remote.getGlobal('argv'))
    console.timeEnd('main')
}, false)

================================================
FILE: ts/shortway.ts
================================================
const keyCodes: { [name: string]: number } = {
    backspace: 8,
    tab: 9,
    enter: 13,
    pause: 19,
    esc: 27,
    space: 32,
    pageup: 33,
    pagedown: 34,
    end: 35,
    home: 36,
    left: 37,
    up: 38,
    right: 39,
    down: 40,
    insert: 45,
    del: 46,
    slash: 191,
    0: 48,
    1: 49,
    2: 50,
    3: 51,
    4: 52,
    5: 53,
    6: 54,
    7: 55,
    8: 56,
    9: 57,
    a: 65,
    b: 66,
    c: 67,
    d: 68,
    e: 69,
    f: 70,
    g: 71,
    h: 72,
    i: 73,
    j: 74,
    k: 75,
    l: 76,
    m: 77,
    n: 78,
    o: 79,
    p: 80,
    q: 81,
    r: 82,
    s: 83,
    t: 84,
    u: 85,
    v: 86,
    w: 87,
    x: 88,
    y: 89,
    z: 90,
    f1: 112,
    f2: 113,
    f3: 114,
    f4: 115,
    f5: 116,
    f6: 117,
    f7: 118,
    f8: 119,
    f9: 120,
    f10: 121,
    f11: 122,
    f12: 123,
    numLock: 144,
    scrollLock: 145,
    ';': 186,
    '=': 187,
    ',': 188,
    '-': 189,
    '.': 190,
    '/': 191,
    '`': 192,
    '[': 219,
    '\\': 220,
    ']': 221,
    "'": 221
}

const includes = (array, item) => array.indexOf(item) > -1

export const shortway = (command, callback) => {
    const keys = command.split('+')
    const key = keys.filter(key => keyCodes[key])[0]
    const keyCode = keyCodes[key]
    const ctrl = keys.some(key => key === 'ctrl')
    const shift = keys.some(key => key === 'shift')
    const alt = keys.some(key => key === 'alt')

    if (!keyCode) throw new Error(`can't find keycode for command ${command}`)
    return function (e) {
        if (e.ctrlKey === ctrl &&
            e.shiftKey === shift &&
            e.altKey === alt &&
            e.keyCode === keyCode) {
            callback(e)
            return false
        }
    }
}

================================================
FILE: tsconfig.json
================================================
{
    "compilerOptions": {
        "outDir": "js",
        "target": "es2017",
        "module": "commonjs",
        "sourceMap": true,
        "lib": [
            "dom",
            "es2017",
            "es2015.promise"
        ]
    }
}

================================================
FILE: updates.json
================================================
{
    "linux-x64-prod": {
        "readme": "JumpFm",
        "update": "https://github.com/JumpFm/jumpfm/releases/download/v1.0.5/JumpFm-1.0.5-x86_64.AppImage",
        "install": "https://github.com/JumpFm/jumpfm/releases/download/v1.0.5/JumpFm-1.0.5-x86_64.AppImage",
        "version": "1.0.5"
    },
    "win32-x64-prod": {
        "readme": "JumpFm",
        "update": "https://github.com/JumpFm/jumpfm/releases/download/v1.0.5/jumpfm-setup-1.0.5.exe",
        "install": "https://github.com/JumpFm/jumpfm/releases/download/v1.0.5/jumpfm-setup-1.0.5.exe",
        "version": "1.0.5"
    },
    "darwin-x64-prod": {
        "readme": "JumpFm",
        "update": "https://github.com/heywoodlh/jumpfm/releases/download/v1.0.2/jumpfm-1.0.2.dmg",
        "install": "https://github.com/heywoodlh/jumpfm/releases/download/v1.0.2/jumpfm-1.0.2.dmg",
        "version": "1.0.2"
    }
}
Download .txt
gitextract_g_cm2yzf/

├── .gitignore
├── .travis.yml
├── .vscode/
│   └── cSpell.json
├── README.md
├── app.js
├── appveyor.yml
├── build/
│   └── superhero.png.icns
├── index.html
├── misc/
│   ├── ascii.txt
│   ├── cookbook.txt
│   ├── icons.awk
│   ├── icons.txt
│   ├── init-demo.sh
│   ├── link-all.sh
│   ├── modd.conf
│   ├── omg-ubunut.txt
│   └── reddit.txt
├── package.json
├── scss/
│   ├── _app.scss
│   ├── _classes.scss
│   ├── _colors.scss
│   ├── _dialog.scss
│   ├── _panel.scss
│   ├── _panels.scss
│   ├── _statusbar.scss
│   ├── _tooltip.scss
│   └── index.scss
├── ts/
│   ├── Dialog.ts
│   ├── Filter.ts
│   ├── Item.ts
│   ├── JumpFm.ts
│   ├── Panel.ts
│   ├── PluginManager.ts
│   ├── Settings.ts
│   ├── StatusBar.ts
│   ├── files.ts
│   ├── icons.ts
│   ├── main.ts
│   └── shortway.ts
├── tsconfig.json
└── updates.json
Download .txt
SYMBOL INDEX (31 symbols across 9 files)

FILE: ts/Dialog.ts
  type SuggestionLi (line 4) | interface SuggestionLi extends Suggestion {
  class Dialog (line 8) | class Dialog implements DialogApi {
    method constructor (line 27) | constructor() {

FILE: ts/Filter.ts
  class Filter (line 5) | class Filter implements FilterApi {
    method constructor (line 11) | constructor() {
    method notifyAll (line 22) | private notifyAll(): any {

FILE: ts/Item.ts
  type attr (line 6) | type attr = 'cur' | 'hidden' | 'selected'
  class Item (line 8) | class Item implements ItemApi {
    method constructor (line 21) | constructor(item: File) {
    method setAttribute (line 63) | setAttribute(name: string, val: string = '') {

FILE: ts/JumpFm.ts
  class JumpFm (line 23) | class JumpFm implements JumpFmApi {
    method constructor (line 92) | constructor(argv: string[]) {

FILE: ts/Panel.ts
  class Panel (line 8) | class Panel implements PanelApi {
    method constructor (line 29) | constructor() {
    method cd (line 167) | cd(pathOrUrl: any) {

FILE: ts/PluginManager.ts
  type checkRes (line 16) | interface checkRes {
  class PluginsLoader (line 44) | class PluginsLoader {
    method constructor (line 49) | constructor(jumpFm: JumpFm, done: (err?) => void) {
    method loadPlugins (line 100) | loadPlugins(pkg) {
    method load (line 112) | load() {
  class PluginManager (line 133) | class PluginManager {
    method constructor (line 136) | constructor(jumpFm) {

FILE: ts/Settings.ts
  type Type (line 5) | type Type = 'string' | 'number'
  class Settings (line 7) | class Settings implements SettingsApi {

FILE: ts/StatusBar.ts
  class Msg (line 3) | class Msg implements MsgAPi {
    method constructor (line 6) | constructor() {
  class Button (line 40) | class Button {
    method constructor (line 44) | constructor(faIcon: string, tooltip: string) {
  class StatusBar (line 53) | class StatusBar implements StatusBarApi {
    method buttonAdd (line 77) | buttonAdd(faIcon: string, tooltip: string, action: () => void) {

FILE: ts/files.ts
  type Plugins (line 5) | interface Plugins {
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (91K chars).
[
  {
    "path": ".gitignore",
    "chars": 68,
    "preview": "node_modules/\ndist/\n.sass-cache/\ncss\n_config.yml\njs\n*.swp\nold\n*.log\n"
  },
  {
    "path": ".travis.yml",
    "chars": 1047,
    "preview": "sudo: required\ndist: trusty\nlanguage: node_js\nnode_js: 6\n\nbranches:\n  only:\n  - master\n  \nbefore_install:\n  - npm i -g n"
  },
  {
    "path": ".vscode/cSpell.json",
    "chars": 597,
    "preview": "// cSpell Settings\n{\n    // Version of the setting file.  Always 0.1\n    \"version\": \"0.1\",\n    // language - current act"
  },
  {
    "path": "README.md",
    "chars": 1390,
    "preview": "[![Build Status](https://travis-ci.org/Gilad-Kutiel-App/jumpfm.svg?branch=master)](https://travis-ci.org/Gilad-Kutiel-Ap"
  },
  {
    "path": "app.js",
    "chars": 1156,
    "preview": "const updater = require('electron-simple-updater');\nconst electron = require('electron')\nconst app = electron.app\nconst "
  },
  {
    "path": "appveyor.yml",
    "chars": 566,
    "preview": "os: unstable\nbranches:\n  only:\n  - master\n\ncache:\n  - node_modules\nenvironment:\n  GH_TOKEN:\n      secure: RcYdy07RY6uQXR"
  },
  {
    "path": "index.html",
    "chars": 1099,
    "preview": "<!DOCTYPE html>\n<html>\n\n<head>\n  <title>JumpFm</title>\n  <link rel=\"stylesheet\"\n    href=\"css/index.css\">\n  <link rel=\"s"
  },
  {
    "path": "misc/ascii.txt",
    "chars": 388,
    "preview": "\n\n       _                       ______          \n      | |                     |  ____|         \n      | |_   _ _ __ __"
  },
  {
    "path": "misc/cookbook.txt",
    "chars": 76,
    "preview": "find {{pwd}} -name {{input}}\nfind {{sel}} -name {{input}}\ncat ~/favorits.txt"
  },
  {
    "path": "misc/icons.awk",
    "chars": 329,
    "preview": "#!/usr/bin/awk -f\nBEGIN { \n\tRS=\"}\"\n\tprint \"{\"\n}\n\nmatch($0, /icon: '([^']+)'.*extensions: (\\[[^\\].]+\\])/, a){\n\tprint \"\\\"\""
  },
  {
    "path": "misc/icons.txt",
    "chars": 40549,
    "preview": "/* tslint:disable max-line-length */\nimport { languages } from './languages';\nimport { FileFormat, IFileCollection } fro"
  },
  {
    "path": "misc/init-demo.sh",
    "chars": 192,
    "preview": "#!/bin/bash\n\nrm -rf ~/demo\nmkdir -p ~/demo/mybooklive/Tv.Show\n\nfor i in {1..5}; do\n\tfolder=~/demo/downloads/Tv.Show.S01E"
  },
  {
    "path": "misc/link-all.sh",
    "chars": 203,
    "preview": "#!/bin/bash\nnpm link jumpfm-clock jumpfm-copy jumpfm-fs jumpfm-gist jumpfm-git-status jumpfm-history jumpfm-jump jumpfm-"
  },
  {
    "path": "misc/modd.conf",
    "chars": 44,
    "preview": "icons.awk {\n\tprep: ./icons.awk icons.txt \n}\n"
  },
  {
    "path": "misc/omg-ubunut.txt",
    "chars": 673,
    "preview": "Hi Joey,\n\nI'm the developer of JumpFm (http://jumpfm.org).\nIts an Electron based (I know, I know.. but its really not th"
  },
  {
    "path": "misc/reddit.txt",
    "chars": 1086,
    "preview": "tl;dr\nI made JumpFm (http://bit.ly/2uBFWIC), need your feedback\n\nHi,\n\nI decided to format my machine last weekend. \nThen"
  },
  {
    "path": "package.json",
    "chars": 1891,
    "preview": "{\n    \"name\": \"jumpfm\",\n    \"version\": \"1.0.6\",\n    \"description\": \"A file manager that lets you jump\",\n    \"author\": {\n"
  },
  {
    "path": "scss/_app.scss",
    "chars": 603,
    "preview": "@import 'colors';\n@font-face {\n    font-family: DroidSansMono;\n    src: url('../fonts/DroidSansMono.ttf');\n}\n\n* {\n    fo"
  },
  {
    "path": "scss/_classes.scss",
    "chars": 241,
    "preview": "@import 'colors';\n.border {\n  border: 1px solid $color-natural;\n}\n\n.txt-no-wrap {\n  white-space: nowrap;\n  text-overflow"
  },
  {
    "path": "scss/_colors.scss",
    "chars": 216,
    "preview": "$color-border:#646464;\n$color-err:#F58E8E;\n$color-natural:#A9D3AB;\n$color-warn:#FED37E;\n$color-info:#7AABD4;\n$color-06:#"
  },
  {
    "path": "scss/_dialog.scss",
    "chars": 973,
    "preview": "@import 'colors';\n@import 'classes';\n#dialog {\n  display: none;\n  position: absolute;\n  top: 20%;\n  left: 0;\n  right: 0;"
  },
  {
    "path": "scss/_panel.scss",
    "chars": 1468,
    "preview": "@import 'colors';\n@import 'classes';\n.panel {\n  display: flex;\n  flex-direction: column;\n  flex-grow: 1;\n  width: 50%;\n "
  },
  {
    "path": "scss/_panels.scss",
    "chars": 73,
    "preview": "#panels {\n    flex-grow: 1;\n    display: flex;\n    flex-direction: row;\n}"
  },
  {
    "path": "scss/_statusbar.scss",
    "chars": 1177,
    "preview": "@import 'colors';\n// \n#statusbar {\n    display: flex;\n    flex-shrink: 0;\n    padding: .1em 0;\n    border-top: 3px solid"
  },
  {
    "path": "scss/_tooltip.scss",
    "chars": 719,
    "preview": "@import 'colors';\n[data-title] {\n    &:before {\n        position: absolute;\n        content: attr(data-title);\n        w"
  },
  {
    "path": "scss/index.scss",
    "chars": 126,
    "preview": "@import 'app';\n@import 'panels';\n@import 'panel';\n@import 'classes';\n@import 'dialog';\n@import 'statusbar';\n@import 'too"
  },
  {
    "path": "ts/Dialog.ts",
    "chars": 3107,
    "preview": "import { Dialog as DialogApi, DialogSpec, Suggestion } from 'jumpfm-api'\nimport { shortway } from \"./shortway\";\n\ninterfa"
  },
  {
    "path": "ts/Filter.ts",
    "chars": 1488,
    "preview": "import { FilterBox as FilterApi } from 'jumpfm-api'\nimport { getKeys } from \"./files\";\nimport { shortway } from \"./short"
  },
  {
    "path": "ts/Item.ts",
    "chars": 2268,
    "preview": "import { Item as ItemApi, File } from 'jumpfm-api'\n\nimport * as moment from 'moment'\nimport * as fileSize from 'filesize"
  },
  {
    "path": "ts/JumpFm.ts",
    "chars": 3479,
    "preview": "import { } from 'electron'\nimport { JumpFm as JumpFmApi } from 'jumpfm-api'\nimport { Panel } from \"./Panel\"\nimport { Sta"
  },
  {
    "path": "ts/Panel.ts",
    "chars": 8033,
    "preview": "import { Panel as PanelApi, Url, File } from 'jumpfm-api'\n\nimport { Item } from './Item'\nimport { Filter } from './Filte"
  },
  {
    "path": "ts/PluginManager.ts",
    "chars": 4026,
    "preview": "import { JumpFm } from 'jumpfm-api'\n\nimport {\n    pluginsPath,\n    pluginsPackageJson,\n    packageJson,\n    savePlugins\n"
  },
  {
    "path": "ts/Settings.ts",
    "chars": 528,
    "preview": "import { Settings as SettingsApi } from 'jumpfm-api'\n\nimport { settings, saveSettings } from './files'\n\ntype Type = 'str"
  },
  {
    "path": "ts/StatusBar.ts",
    "chars": 2217,
    "preview": "import { StatusBar as StatusBarApi, Msg as MsgAPi } from 'jumpfm-api'\n\nclass Msg implements MsgAPi {\n    readonly divMsg"
  },
  {
    "path": "ts/files.ts",
    "chars": 1390,
    "preview": "import * as fs from 'fs-extra';\nimport * as homedir from 'homedir';\nimport * as path from 'path';\n\nexport interface Plug"
  },
  {
    "path": "ts/icons.ts",
    "chars": 303,
    "preview": "\nconst icons = require('../icons.json')\nconst extensions = {}\nfor (var icon in icons) {\n    icons[icon].forEach(ext => {"
  },
  {
    "path": "ts/main.ts",
    "chars": 205,
    "preview": "document.addEventListener('DOMContentLoaded', () => {\n    console.time('main')\n    new (require('./js/JumpFm.js').JumpFm"
  },
  {
    "path": "ts/shortway.ts",
    "chars": 1740,
    "preview": "const keyCodes: { [name: string]: number } = {\n    backspace: 8,\n    tab: 9,\n    enter: 13,\n    pause: 19,\n    esc: 27,\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 240,
    "preview": "{\n    \"compilerOptions\": {\n        \"outDir\": \"js\",\n        \"target\": \"es2017\",\n        \"module\": \"commonjs\",\n        \"so"
  },
  {
    "path": "updates.json",
    "chars": 882,
    "preview": "{\n    \"linux-x64-prod\": {\n        \"readme\": \"JumpFm\",\n        \"update\": \"https://github.com/JumpFm/jumpfm/releases/downl"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the JumpFm/jumpfm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (84.8 KB), approximately 24.4k tokens, and a symbol index with 31 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!