├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── index.js ├── license ├── package.json ├── readme.md ├── test.css ├── test.html └── test.scss /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [{package.json,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 'node' 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** @babel */ 2 | import {CompositeDisposable} from 'atom'; 3 | import postcss from 'postcss'; 4 | import perfectionist from 'perfectionist'; 5 | import postcssSafeParser from 'postcss-safe-parser'; 6 | import postcssScss from 'postcss-scss'; 7 | 8 | const SUPPORTED_SCOPES = new Set([ 9 | 'source.css', 10 | 'source.css.scss' 11 | ]); 12 | 13 | function init(editor, onSave) { 14 | const selectedText = onSave ? null : editor.getSelectedText(); 15 | const text = selectedText || editor.getText(); 16 | const config = atom.config.get('perfectionist'); 17 | const parser = editor.getGrammar().scopeName === 'source.css' ? postcssSafeParser : postcssScss; 18 | 19 | if (config.indentType === 'tab') { 20 | config.indentChar = '\t'; 21 | config.indentSize = 1; 22 | } 23 | 24 | postcss(perfectionist(config)).process(text, {parser}).then(result => { 25 | result.warnings().forEach(x => { 26 | console.warn(x.toString()); 27 | atom.notifications.addWarning('Perfectionist', {detail: x.toString()}); 28 | }); 29 | 30 | const cursorPosition = editor.getCursorBufferPosition(); 31 | const line = atom.views.getView(editor).getFirstVisibleScreenRow() + 32 | editor.getVerticalScrollMargin(); 33 | 34 | if (selectedText) { 35 | editor.setTextInBufferRange(editor.getSelectedBufferRange(), result.css); 36 | } else { 37 | editor.getBuffer().setTextViaDiff(result.css); 38 | } 39 | 40 | editor.setCursorBufferPosition(cursorPosition); 41 | 42 | if (editor.getScreenLineCount() > line) { 43 | editor.scrollToScreenPosition([line, 0]); 44 | } 45 | }).catch(err => { 46 | if (err.name === 'CssSyntaxError') { 47 | err.message += err.showSourceCode(); 48 | } 49 | 50 | console.error(err); 51 | atom.notifications.addError('Perfectionist', {detail: err.message}); 52 | }); 53 | } 54 | 55 | export const config = { 56 | formatOnSave: { 57 | type: 'boolean', 58 | default: false 59 | }, 60 | cascade: { 61 | description: 'Visual cascading of vendor prefixed properties. Note that this transform only applies to the `expanded` format.', 62 | type: 'boolean', 63 | default: true 64 | }, 65 | colorCase: { 66 | description: 'Transform hexadecimal colors to the chosen case.', 67 | type: 'string', 68 | default: 'lower', 69 | enum: [ 70 | 'lower', 71 | 'upper' 72 | ] 73 | }, 74 | colorShorthand: { 75 | description: 'Shorten hexadecimal colors.', 76 | type: 'boolean', 77 | default: true 78 | }, 79 | format: { 80 | description: 'Note that the `compressed` format only facilitates simple whitespace compression around selectors & declarations. For more powerful compression, see [cssnano](https://github.com/ben-eb/cssnano).', 81 | type: 'string', 82 | default: 'expanded', 83 | enum: [ 84 | 'expanded', 85 | 'compact', 86 | 'compressed' 87 | ] 88 | }, 89 | indentType: { 90 | description: 'Indentation character.', 91 | type: 'string', 92 | default: 'space', 93 | enum: [ 94 | 'space', 95 | 'tab' 96 | ] 97 | }, 98 | indentSize: { 99 | description: 'This number will be used as a basis for all indent levels, using the expanded format.', 100 | type: 'number', 101 | default: 4 102 | }, 103 | trimLeadingZero: { 104 | description: 'Trim leading zero for fractional numbers less than 1.', 105 | type: 'boolean', 106 | default: true 107 | }, 108 | trimTrailingZeros: { 109 | description: 'Trim trailing zeros in numbers.', 110 | type: 'boolean', 111 | default: true 112 | }, 113 | maxAtRuleLength: { 114 | description: 'If set to a positive integer, set a maximum width for at-rule parameters; if they exceed this, they will be split up over multiple lines. If false, this behaviour will not be performed. Note that this transform only applies to the `expanded` format.', 115 | type: [ 116 | 'boolean', 117 | 'number' 118 | ], 119 | default: 80 120 | }, 121 | maxSelectorLength: { 122 | description: 'If set to a positive integer, set a maximum width for a selector string; if it exceeds this, it will be split up over multiple lines. If false, this behaviour will not be performed. Note that this transform is excluded from the `compressed` format.', 123 | type: [ 124 | 'boolean', 125 | 'number' 126 | ], 127 | default: 80 128 | }, 129 | maxValueLength: { 130 | description: 'If set to a positive integer, set a maximum width for a property value; if it exceeds this, it will be split up over multiple lines. If false, this behaviour will not be performed. Note that this transform only applies to the `expanded` format.', 131 | type: [ 132 | 'boolean', 133 | 'number' 134 | ], 135 | default: 80 136 | }, 137 | zeroLengthNoUnit: { 138 | description: 'Trim units after zero length.', 139 | type: 'boolean', 140 | default: true 141 | } 142 | }; 143 | 144 | export function deactivate() { 145 | this.subscriptions.dispose(); 146 | } 147 | 148 | export function activate() { 149 | this.subscriptions = new CompositeDisposable(); 150 | 151 | this.subscriptions.add(atom.workspace.observeTextEditors(editor => { 152 | editor.getBuffer().onWillSave(() => { 153 | const isCSS = SUPPORTED_SCOPES.has(editor.getGrammar().scopeName); 154 | 155 | if (isCSS && atom.config.get('perfectionist.formatOnSave')) { 156 | init(editor, true); 157 | } 158 | }); 159 | })); 160 | 161 | this.subscriptions.add(atom.commands.add('atom-workspace', 'perfectionist:beautify-css', () => { 162 | const editor = atom.workspace.getActiveTextEditor(); 163 | 164 | if (editor) { 165 | init(editor); 166 | } 167 | })); 168 | } 169 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Sindre Sorhus (sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "perfectionist", 3 | "version": "2.0.0", 4 | "description": "Beautify CSS and SCSS", 5 | "license": "MIT", 6 | "repository": "sindresorhus/atom-perfectionist", 7 | "author": { 8 | "name": "Sindre Sorhus", 9 | "email": "sindresorhus@gmail.com", 10 | "url": "sindresorhus.com" 11 | }, 12 | "private": true, 13 | "engines": { 14 | "atom": ">=1.13.0" 15 | }, 16 | "scripts": { 17 | "test": "xo" 18 | }, 19 | "keywords": [ 20 | "css", 21 | "scss", 22 | "beautify", 23 | "format", 24 | "style", 25 | "pretty", 26 | "sass" 27 | ], 28 | "dependencies": { 29 | "perfectionist": "^2.4.0", 30 | "postcss": "^5.0.4", 31 | "postcss-safe-parser": "^2.0.0", 32 | "postcss-scss": "^0.4.0" 33 | }, 34 | "devDependencies": { 35 | "xo": "*" 36 | }, 37 | "activationCommands": { 38 | "atom-workspace": [ 39 | "core:save", 40 | "perfectionist:beautify-css" 41 | ] 42 | }, 43 | "xo": { 44 | "globals": [ 45 | "atom" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Deprecated 2 | 3 | The Perfectionist project is no longer maintained. 4 | 5 | --- 6 | 7 | # perfectionist 8 | 9 | > Beautify CSS and SCSS with [Perfectionist](https://github.com/ben-eb/perfectionist) 10 | 11 | *Issues with the output should be reported on the Perfectionist [issue tracker](https://github.com/ben-eb/perfectionist/issues).* 12 | 13 | 14 | ## Install 15 | 16 | ``` 17 | $ apm install perfectionist 18 | ``` 19 | 20 | Or, Settings → Install → Search for `perfectionist` 21 | 22 | 23 | ## Usage 24 | 25 | Open the Command Palette and type `beautify css` or `perfectionist`. 26 | 27 | You can also select some CSS or SCSS in a HTML file and do the above. 28 | 29 | There's a `Format On Save` option and more in the settings. 30 | 31 | 32 | ## Keyboard shortcut 33 | 34 | Set the keyboard shortcut you want in your [keymap](http://flight-manual.atom.io/using-atom/sections/basic-customization/#customizing-keybindings): 35 | 36 | ```cson 37 | 'atom-text-editor': 38 | 'cmd-shift-x': 'perfectionist:beautify-css' 39 | ``` 40 | 41 | 42 | ## License 43 | 44 | MIT © [Sindre Sorhus](https://sindresorhus.com) 45 | -------------------------------------------------------------------------------- /test.css: -------------------------------------------------------------------------------- 1 | div {display:flex;} 2 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | test 4 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test.scss: -------------------------------------------------------------------------------- 1 | $font-stack: Helvetica, sans-serif; // comment 2 | body{h1{font:100% /* comment */ $font-stack;}} 3 | --------------------------------------------------------------------------------