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
================================================
[](https://travis-ci.org/Gilad-Kutiel-App/jumpfm) [](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:

================================================
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"
}
}
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
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": "[](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.