atom-beautify/lib/atom-beautify.js

160 lines
4.1 KiB
JavaScript

/* global atom */
'use strict';
var beautifyJS = require('js-beautify');
var beautifyHTML = require('js-beautify').html;
var beautifyCSS = require('js-beautify').css;
var fs = require('fs');
var path = require('path');
var cc = require('config-chain');
var nopt = require('nopt');
var extend = require('extend');
// TODO: Copied from jsbeautify, please update it from time to time
var knownOpts = {
// Beautifier
'indent_size': Number,
'indent_char': String,
'indent_level': Number,
'indent_with_tabs': Boolean,
'preserve_newlines': Boolean,
'max_preserve_newlines': Number,
'space_in_paren': Boolean,
'jslint_happy': Boolean,
// TODO: expand-strict is obsolete, now identical to expand. Remove in future version
'brace_style': ['collapse', 'expand', 'end-expand', 'expand-strict'],
'break_chained_methods': Boolean,
'keep_array_indentation': Boolean,
'unescape_strings': Boolean,
'wrap_line_length': Number,
'e4x': Boolean,
// HTML-only
'max_char': Number, // obsolete since 1.3.5
'unformatted': [String, Array],
'indent_inner_html': [Boolean],
'indent_scripts': ['keep', 'separate', 'normal'],
// CLI
'version': Boolean,
'help': Boolean,
'files': [path, Array],
'outfile': path,
'replace': Boolean,
'quiet': Boolean,
'type': ['js', 'css', 'html'],
'config': path
};
var Subscriber = require('emissary').Subscriber;
var plugin = module.exports;
Subscriber.extend(plugin);
function verifyExists(fullPath) {
return fs.existsSync(fullPath) ? fullPath : null;
}
function findRecursive(dir, fileName) {
var fullPath = path.join(dir, fileName);
var nextDir = path.dirname(dir);
var result = verifyExists(fullPath);
if (!result && (nextDir !== dir)) {
result = findRecursive(nextDir, fileName);
}
return result;
}
function getUserHome() {
return process.env.HOME || process.env.USERPROFILE;
}
function cleanOptions(data, types) {
nopt.clean(data, types);
return data;
}
function beautify() {
var text;
var editor = atom.workspace.getActiveEditor();
var isSelection = !! editor.getSelectedText();
var softTabs = editor.softTabs;
var tabLength = editor.getTabLength();
var beautifyOptions = {
'indent_size': softTabs ? tabLength : 1,
'indent_char': softTabs ? ' ' : '\t'
};
// Look for .jsbeautifierrc in file and home path, check env variables
var editedFilePath = editor.getPath();
var cfg = cc(
cleanOptions(cc.env('jsbeautify_'), knownOpts),
editedFilePath ? findRecursive(path.dirname(editedFilePath),
'.jsbeautifyrc') : null,
verifyExists(path.join(getUserHome() || '', '.jsbeautifyrc'))
).list;
// cc(...).snapshot SHOULD contain the same what I construct below,
// however I have not the faintest idea why it doesn't work here.
// It works at js-beautify cli, but not here. Weird.
var collectedConfig = {};
for (var idx = cfg.length - 1; idx >= 0; idx--) {
collectedConfig = extend(cfg[idx], collectedConfig);
}
// Override the indenting options from the editor
beautifyOptions = extend(collectedConfig, beautifyOptions);
if (isSelection) {
text = editor.getSelectedText();
} else {
text = editor.getText();
}
switch (editor.getGrammar().name) {
case 'JavaScript':
text = beautifyJS(text, beautifyOptions);
break;
case 'HTML':
case 'XML':
text = beautifyHTML(text, beautifyOptions);
break;
case 'CSS':
text = beautifyCSS(text, beautifyOptions);
break;
default:
return;
}
if (isSelection) {
editor.setTextInBufferRange(
editor.getSelectedBufferRange(),
text
);
} else {
editor.setText(text);
}
}
function handleSafeEvent() {
atom.workspace.eachEditor(function(editor) {
var buffer = editor.getBuffer();
plugin.unsubscribe(buffer);
if (atom.config.get('atom-beautify.beautifyOnSave')) {
var events = 'will-be-saved';
plugin.subscribe(buffer, events, beautify);
}
});
}
plugin.configDefaults = {
beautifyOnSave: false
};
plugin.activate = function() {
handleSafeEvent();
plugin.subscribe(atom.config.observe(
'atom-beautify.beautifyOnSave',
handleSafeEvent));
return atom.workspaceView.command('beautify', beautify);
};