commit
fe0dc7bccf
98
README.md
98
README.md
|
@ -1,19 +1,105 @@
|
||||||
# atom-beautify package
|
# [atom-beautify](https://github.com/donaldpipowitch/atom-beautify)
|
||||||
|
|
||||||
[Beautify](https://github.com/einars/js-beautify) HTML, CSS and Javascript in Atom.
|
> [Beautify](https://github.com/einars/js-beautify)
|
||||||
|
HTML (including [Handlebars](http://handlebarsjs.com/)),
|
||||||
|
CSS (including [Sass](http://sass-lang.com/) and [LESS](http://lesscss.org/))
|
||||||
|
and JavaScript in Atom.
|
||||||
|
|
||||||
*Attention*: A different package with a similar name exist. Maybe you want to visit this one: [Beautifier](https://atom.io/packages/atom-beautifier).
|
## Language Support
|
||||||
|
|
||||||
|
- JavaScript
|
||||||
|
- HTML, including
|
||||||
|
- [Handlebars](http://handlebarsjs.com/)
|
||||||
|
- XML is supported as an *experimental feature*.
|
||||||
|
- CSS, including
|
||||||
|
- [Sass](http://sass-lang.com/)
|
||||||
|
- [LESS](http://lesscss.org/)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Open the Command Palette, and type `Beautify`. This will beautify JS, HTML or CSS files. (XML is supported as an experimental feature.) It will only beautify selected text, if a selection is found - if not, the whole file will be beautified.
|
Open the [Command Palette](https://github.com/atom/command-palette), and type `Beautify`.
|
||||||
|
|
||||||
|
It will only beautify selected text, if a selection is found - if not, the whole file will be beautified.
|
||||||
|
|
||||||
|
### Shortcut
|
||||||
|
|
||||||
You can also type `ctrl-alt-b` as a shortcut or click `Packages > Beautify` in the menu.
|
You can also type `ctrl-alt-b` as a shortcut or click `Packages > Beautify` in the menu.
|
||||||
|
|
||||||
|
### Package Options
|
||||||
|
|
||||||
You can also choose to beautify on every file save.
|
You can also choose to beautify on every file save.
|
||||||
|
|
||||||
You can change the current config by either using `.jsbeautifyrc` for all files or a non-standard variante with settings for every file type. You can see examples of both way inside [`examples/`](https://github.com/donaldpipowitch/atom-beautify/examples)
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Edit your `.jsbeautifyrc` file in any of the following locations:
|
||||||
|
|
||||||
|
- Same directory as current file
|
||||||
|
- Project root
|
||||||
|
`atom-beautify` will recursively look up from the current file's directory to find `.jsbeautifyrc`.
|
||||||
|
- Your User's Home directory
|
||||||
|
|
||||||
|
**Note**: *Comments are supported in `.jsbeautifyrc` thanks to [strip-json-comments](https://github.com/sindresorhus/strip-json-comments).*
|
||||||
|
|
||||||
|
See examples of both way inside [`examples/`](https://github.com/donaldpipowitch/atom-beautify/tree/master/examples)
|
||||||
|
|
||||||
|
### Simple
|
||||||
|
|
||||||
|
See [examples/simple-jsbeautifyrc/.jsbeautifyrc](https://github.com/donaldpipowitch/atom-beautify/blob/master/examples/simple-jsbeautifyrc/.jsbeautifyrc).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"indent_size": 2,
|
||||||
|
"indent_char": " ",
|
||||||
|
"other": " ",
|
||||||
|
"indent_level": 0,
|
||||||
|
"indent_with_tabs": false,
|
||||||
|
"preserve_newlines": true,
|
||||||
|
"max_preserve_newlines": 2,
|
||||||
|
"jslint_happy": true,
|
||||||
|
"indent_handlebars": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nested
|
||||||
|
|
||||||
|
See [examples/nested-jsbeautifyrc/.jsbeautifyrc](https://github.com/donaldpipowitch/atom-beautify/blob/master/examples/nested-jsbeautifyrc/.jsbeautifyrc).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"brace_style": "collapse",
|
||||||
|
"indent_char": " ",
|
||||||
|
"indent_scripts": "normal",
|
||||||
|
"indent_size": 6,
|
||||||
|
"max_preserve_newlines": 1,
|
||||||
|
"preserve_newlines": true,
|
||||||
|
"unformatted": ["a", "sub", "sup", "b", "i", "u"],
|
||||||
|
"wrap_line_length": 0
|
||||||
|
},
|
||||||
|
"css": {
|
||||||
|
"indent_char": " ",
|
||||||
|
"indent_size": 4
|
||||||
|
},
|
||||||
|
"js": {
|
||||||
|
"indent_size": 2,
|
||||||
|
"indent_char": " ",
|
||||||
|
"indent_level": 0,
|
||||||
|
"indent_with_tabs": false,
|
||||||
|
"preserve_newlines": true,
|
||||||
|
"max_preserve_newlines": 2,
|
||||||
|
"jslint_happy": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
[See all contributors on GitHub](https://github.com/donaldpipowitch/atom-beautify/graphs/contributors).
|
||||||
|
|
||||||
|
Please update the [CHANGELOG.md](https://github.com/donaldpipowitch/atom-beautify/blob/master/CHANGELOG.md)
|
||||||
|
file and submit a [Pull Request on GitHub](https://help.github.com/articles/using-pull-requests).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT © [Donald Pipowitch](https://github.com/donaldpipowitch)
|
[MIT](https://github.com/donaldpipowitch/atom-beautify/blob/master/LICENSE.md) © [Donald Pipowitch](https://github.com/donaldpipowitch)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
{
|
{
|
||||||
"indent_size": 2,
|
"indent_size": 2,
|
||||||
"indent_char": " ",
|
"indent_char": " ",
|
||||||
|
"other": " ",
|
||||||
"indent_level": 0,
|
"indent_level": 0,
|
||||||
"indent_with_tabs": false,
|
"indent_with_tabs": false,
|
||||||
"preserve_newlines": true,
|
"preserve_newlines": true,
|
||||||
"max_preserve_newlines": 2,
|
"max_preserve_newlines": 2,
|
||||||
"jslint_happy": true
|
"jslint_happy": true,
|
||||||
|
"indent_handlebars": true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
{{#if}}
|
||||||
|
{{#each}}
|
||||||
|
{{#if}}
|
||||||
|
content
|
||||||
|
{{/if}}
|
||||||
|
{{#if}}
|
||||||
|
content
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
|
@ -18,6 +18,7 @@ var knownOpts = {
|
||||||
'indent_char': String,
|
'indent_char': String,
|
||||||
'indent_level': Number,
|
'indent_level': Number,
|
||||||
'indent_with_tabs': Boolean,
|
'indent_with_tabs': Boolean,
|
||||||
|
'indent_handlebars': Boolean,
|
||||||
'preserve_newlines': Boolean,
|
'preserve_newlines': Boolean,
|
||||||
'max_preserve_newlines': Number,
|
'max_preserve_newlines': Number,
|
||||||
'space_in_paren': Boolean,
|
'space_in_paren': Boolean,
|
||||||
|
@ -49,24 +50,8 @@ var Subscriber = require('emissary').Subscriber;
|
||||||
var plugin = module.exports;
|
var plugin = module.exports;
|
||||||
Subscriber.extend(plugin);
|
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() {
|
function getUserHome() {
|
||||||
return process.env.HOME || process.env.USERPROFILE;
|
return process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanOptions(data, types) {
|
function cleanOptions(data, types) {
|
||||||
|
@ -96,14 +81,84 @@ function setCursors(editor, posArray) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyExists(fullPath) {
|
||||||
|
return fs.existsSync(fullPath) ? fullPath : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage for memoized results from find file
|
||||||
|
// Should prevent lots of directory traversal &
|
||||||
|
// lookups when liniting an entire project
|
||||||
|
var findFileResults = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for a file with a specified name starting with
|
||||||
|
* 'dir' and going all the way up either until it finds the file
|
||||||
|
* or hits the root.
|
||||||
|
*
|
||||||
|
* @param {string} name filename to search for (e.g. .jshintrc)
|
||||||
|
* @param {string} dir directory to start search from (default:
|
||||||
|
* current working directory)
|
||||||
|
*
|
||||||
|
* @returns {string} normalized filename
|
||||||
|
*/
|
||||||
|
function findFile(name, dir) {
|
||||||
|
dir = dir || process.cwd();
|
||||||
|
|
||||||
|
var filename = path.normalize(path.join(dir, name));
|
||||||
|
if (findFileResults[filename] !== undefined) {
|
||||||
|
return findFileResults[filename];
|
||||||
|
}
|
||||||
|
|
||||||
|
var parent = path.resolve(dir, '../');
|
||||||
|
|
||||||
|
if (verifyExists(filename)) {
|
||||||
|
findFileResults[filename] = filename;
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir === parent) {
|
||||||
|
findFileResults[filename] = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findFile(name, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to find a configuration file in either project directory
|
||||||
|
* or in the home directory. Configuration files are named
|
||||||
|
* '.jsbeautifyrc'.
|
||||||
|
*
|
||||||
|
* @param {string} config name of the configuration file
|
||||||
|
* @param {string} file path to the file to be linted
|
||||||
|
* @returns {string} a path to the config file
|
||||||
|
*/
|
||||||
|
function findConfig(config, file) {
|
||||||
|
var dir = path.dirname(path.resolve(file));
|
||||||
|
var envs = getUserHome();
|
||||||
|
var home = path.normalize(path.join(envs, config));
|
||||||
|
|
||||||
|
var proj = findFile(config, dir);
|
||||||
|
if (proj) {
|
||||||
|
return proj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verifyExists(home)) {
|
||||||
|
return home;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function beautify() {
|
function beautify() {
|
||||||
|
|
||||||
var text;
|
var text;
|
||||||
var editor = atom.workspace.getActiveEditor();
|
var editor = atom.workspace.getActiveEditor();
|
||||||
var isSelection = !! editor.getSelectedText();
|
var isSelection = !! editor.getSelectedText();
|
||||||
var softTabs = editor.softTabs;
|
var softTabs = editor.softTabs;
|
||||||
var tabLength = editor.getTabLength();
|
var tabLength = editor.getTabLength();
|
||||||
|
|
||||||
var beautifyOptions = {
|
var defaultOptions = {
|
||||||
'indent_size': softTabs ? tabLength : 1,
|
'indent_size': softTabs ? tabLength : 1,
|
||||||
'indent_char': softTabs ? ' ' : '\t',
|
'indent_char': softTabs ? ' ' : '\t',
|
||||||
'indent_with_tabs': !softTabs
|
'indent_with_tabs': !softTabs
|
||||||
|
@ -111,53 +166,32 @@ function beautify() {
|
||||||
|
|
||||||
// Look for .jsbeautifierrc in file and home path, check env variables
|
// Look for .jsbeautifierrc in file and home path, check env variables
|
||||||
var editedFilePath = editor.getPath();
|
var editedFilePath = editor.getPath();
|
||||||
var rcInRecursiveCwd;
|
|
||||||
if (editedFilePath && (rcInRecursiveCwd = findRecursive(path.dirname(
|
|
||||||
editedFilePath), '.jsbeautifyrc')) === editedFilePath) {
|
|
||||||
rcInRecursiveCwd = null;
|
|
||||||
}
|
|
||||||
var rcInHomePath;
|
|
||||||
if (editedFilePath && (rcInHomePath = verifyExists(path.join(getUserHome() ||
|
|
||||||
'', '.jsbeautifyrc'))) === editedFilePath) {
|
|
||||||
rcInHomePath = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var externalOptions;
|
function getConfig(startPath) {
|
||||||
|
// Verify that startPath is a string
|
||||||
|
startPath = (typeof startPath === 'string') ? startPath : __dirname || '';
|
||||||
|
// Get the path to the config file
|
||||||
|
var configPath = findConfig('.jsbeautifyrc', startPath);
|
||||||
|
|
||||||
if (rcInRecursiveCwd) {
|
var externalOptions;
|
||||||
externalOptions = JSON.parse(fs.readFileSync(rcInRecursiveCwd, {
|
if (configPath) {
|
||||||
encoding: 'utf8'
|
var strip = require('strip-json-comments');
|
||||||
}));
|
try {
|
||||||
} else if (rcInHomePath) {
|
externalOptions = JSON.parse(strip(fs.readFileSync(configPath, {
|
||||||
externalOptions = JSON.parse(fs.readFileSync(rcInHomePath, {
|
encoding: 'utf8'
|
||||||
encoding: 'utf8'
|
})));
|
||||||
}));
|
} catch (e) {
|
||||||
} else {
|
externalOptions = {};
|
||||||
externalOptions = {};
|
}
|
||||||
}
|
} else {
|
||||||
|
externalOptions = {};
|
||||||
var containsNested = false;
|
|
||||||
var collectedConfig = {};
|
|
||||||
var key;
|
|
||||||
|
|
||||||
// Check to see if config file uses nested object format to split up js/css/html options
|
|
||||||
for (key in externalOptions) {
|
|
||||||
if (typeof externalOptions[key] === 'object') {
|
|
||||||
containsNested = true;
|
|
||||||
}
|
}
|
||||||
|
return externalOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a flat object of config options if nested format was used
|
// Get the path to the config file
|
||||||
if (!containsNested) {
|
var projectOptions = getConfig(editedFilePath);
|
||||||
collectedConfig = externalOptions;
|
var homeOptions = getConfig(getUserHome());
|
||||||
} else {
|
|
||||||
for (key in externalOptions) {
|
|
||||||
_.merge(collectedConfig, externalOptions[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beautifyOptions = extend(collectedConfig, beautifyOptions);
|
|
||||||
beautifyOptions = cleanOptions(beautifyOptions, knownOpts);
|
|
||||||
|
|
||||||
if (isSelection) {
|
if (isSelection) {
|
||||||
text = editor.getSelectedText();
|
text = editor.getSelectedText();
|
||||||
|
@ -166,17 +200,68 @@ function beautify() {
|
||||||
}
|
}
|
||||||
var oldText = text;
|
var oldText = text;
|
||||||
|
|
||||||
|
// All of the options
|
||||||
|
// Listed in order from default (base) to the one with the highest priority
|
||||||
|
// Left = Default, Right = Will override the left.
|
||||||
|
var allOptions = [defaultOptions, homeOptions, projectOptions];
|
||||||
|
|
||||||
|
function getOptions(selection, allOptions) {
|
||||||
|
|
||||||
|
// Reduce all options into correctly merged options.
|
||||||
|
var options = _.reduce(allOptions, function(result, currOptions) {
|
||||||
|
|
||||||
|
var containsNested = false;
|
||||||
|
var collectedConfig = {};
|
||||||
|
var key;
|
||||||
|
|
||||||
|
// Check to see if config file uses nested object format to split up js/css/html options
|
||||||
|
for (key in currOptions) {
|
||||||
|
if (typeof currOptions[key] === 'object') {
|
||||||
|
containsNested = true;
|
||||||
|
break; // Found, break out of loop, no need to continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a flat object of config options if nested format was used
|
||||||
|
if (!containsNested) {
|
||||||
|
collectedConfig = currOptions;
|
||||||
|
} else {
|
||||||
|
// Merge with selected options
|
||||||
|
// where `selection` could be `html`, `js`, 'css', etc
|
||||||
|
_.merge(collectedConfig, currOptions[selection]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return extend(result, collectedConfig);
|
||||||
|
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Clean.
|
||||||
|
// There is a bug in nopt
|
||||||
|
// See https://github.com/npm/nopt/issues/38#issuecomment-45971505
|
||||||
|
//console.log('pre-clean', JSON.stringify(options));
|
||||||
|
//options = cleanOptions(options, knownOpts);
|
||||||
|
//console.log('post-clean', JSON.stringify(options));
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
switch (editor.getGrammar().name) {
|
switch (editor.getGrammar().name) {
|
||||||
case 'JavaScript':
|
case 'JavaScript':
|
||||||
text = beautifyJS(text, beautifyOptions);
|
text = beautifyJS(text, getOptions('js', allOptions));
|
||||||
break;
|
break;
|
||||||
|
case 'Handlebars':
|
||||||
|
defaultOptions.indent_handlebars = true; // jshint ignore: line
|
||||||
case 'HTML (Liquid)':
|
case 'HTML (Liquid)':
|
||||||
case 'HTML':
|
case 'HTML':
|
||||||
case 'XML':
|
case 'XML':
|
||||||
text = beautifyHTML(text, beautifyOptions);
|
text = beautifyHTML(text, getOptions('html', allOptions));
|
||||||
break;
|
break;
|
||||||
|
case 'Sass':
|
||||||
|
case 'SCSS':
|
||||||
|
case 'LESS':
|
||||||
case 'CSS':
|
case 'CSS':
|
||||||
text = beautifyCSS(text, beautifyOptions);
|
text = beautifyCSS(text, getOptions('css', allOptions));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
@ -202,7 +287,7 @@ function beautify() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSafeEvent() {
|
function handleSaveEvent() {
|
||||||
atom.workspace.eachEditor(function (editor) {
|
atom.workspace.eachEditor(function (editor) {
|
||||||
var buffer = editor.getBuffer();
|
var buffer = editor.getBuffer();
|
||||||
plugin.unsubscribe(buffer);
|
plugin.unsubscribe(buffer);
|
||||||
|
@ -219,9 +304,9 @@ plugin.configDefaults = {
|
||||||
};
|
};
|
||||||
|
|
||||||
plugin.activate = function () {
|
plugin.activate = function () {
|
||||||
handleSafeEvent();
|
handleSaveEvent();
|
||||||
plugin.subscribe(atom.config.observe(
|
plugin.subscribe(atom.config.observe(
|
||||||
'atom-beautify.beautifyOnSave',
|
'atom-beautify.beautifyOnSave',
|
||||||
handleSafeEvent));
|
handleSaveEvent));
|
||||||
return atom.workspaceView.command('beautify', beautify);
|
return atom.workspaceView.command('beautify', beautify);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,8 +17,9 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"emissary": "^1.0.0",
|
"emissary": "^1.0.0",
|
||||||
"extend": "^1.2.1",
|
"extend": "^1.2.1",
|
||||||
"js-beautify": "~1.4.2",
|
"js-beautify": "~1.5.1",
|
||||||
"nopt": "^2.2.1",
|
"nopt": "^3.0.0",
|
||||||
"lodash": "2.4.1"
|
"lodash": "2.4.1",
|
||||||
|
"strip-json-comments": "^0.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue