├── Default (Linux).sublime-keymap ├── Default (OSX).sublime-keymap ├── Default (Windows).sublime-keymap ├── Main.sublime-menu ├── README.md ├── css_to_sass.py ├── css_to_sass.sublime-settings ├── messages.json └── messages ├── 1.1.0.txt ├── 1.2.0.txt └── install.txt /Default (Linux).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+v"], "command": "css_to_sass" } 3 | ] 4 | -------------------------------------------------------------------------------- /Default (OSX).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["command+v"], "command": "css_to_sass" } 3 | ] 4 | -------------------------------------------------------------------------------- /Default (Windows).sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { "keys": ["ctrl+v"], "command": "css_to_sass" } 3 | ] 4 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences", 4 | "mnemonic": "n", 5 | "id": "preferences", 6 | "children": 7 | [ 8 | { 9 | "caption": "Package Settings", 10 | "mnemonic": "P", 11 | "id": "package-settings", 12 | "children": 13 | [ 14 | { 15 | "caption": "CSS To SASS And Stylus Converter", 16 | "children": 17 | [ 18 | { 19 | "command": "open_file", 20 | "args": {"file": "${packages}/CSS To Sass And Stylus Converter/css_to_sass.sublime-settings"}, 21 | "caption": "Settings – Default" 22 | }, 23 | { 24 | "command": "open_file", 25 | "args": {"file": "${packages}/User/css_to_sass.sublime-settings"}, 26 | "caption": "Settings – User" 27 | }, 28 | { "caption": "-" } 29 | ] 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | ] 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSS to SASS and Stylus converter for Sublime Text 3 2 | 3 | [![5k](https://cdn.rawgit.com/lnikell/wiki/master/5k.svg)](https://packagecontrol.io/packages/CSS%20To%20SASS%20And%20Stylus%20Converter) 4 | 5 | **STOP WASTING YOUR TIME** removing brackets, semicolons and formating any css inserted from your browser to Sublime Text. 6 | 7 | ![Example usage] 8 | (https://habrastorage.org/files/1cc/aa6/0bb/1ccaa60bb0924c8b8976b99acf0e5fd9.gif) 9 | 10 | You could also copy something like this: 11 | ```css 12 | { 13 | display: block; 14 | color: #ffffff; 15 | } 16 | ``` 17 | And plugin will transform it to: 18 | ```css 19 | display: block 20 | color: #ffffff 21 | ``` 22 | 23 | ## Features 24 | - works without any gems or npm packages 25 | - supports nested selectors 26 | - unprefixing (comming soon) 27 | 28 | ## Installation 29 | ### via Package Control 30 | - Open the Command Pallete (ctrl+shift+P or cmd+shift+P); 31 | - Type "Install Package" 32 | - Type "css to sass converter" and hit return. 33 | 34 | ## Configuration options 35 | 36 | ### colon 37 | **Default**: `true`. 38 | Add semicolon after property name or not. Makes sense only for stylus. 39 | 40 | ## Default key bindings 41 | 42 | `Ctrl+V` on Windows/Linux 43 | 44 | `Cmd+V` on OS X 45 | -------------------------------------------------------------------------------- /css_to_sass.py: -------------------------------------------------------------------------------- 1 | import sublime, sublime_plugin 2 | import re 3 | 4 | class CssToSass(sublime_plugin.TextCommand): 5 | options = { 6 | 'openingBracket': '', 7 | 'closingBracket': '', 8 | 'colon': ':', 9 | 'unPrefix': False, 10 | 'keepColons': False, 11 | } 12 | 13 | depth = 0 14 | def run(self, edit): 15 | filename = self.view.file_name() 16 | 17 | type = 'unknown' 18 | 19 | if filename: 20 | if filename.endswith('.sass'): type = 'sass' 21 | elif filename.endswith('.styl'): type = 'stylus' 22 | else: 23 | if self.view.match_selector(0, 'source.sass'): type = 'sass' 24 | elif self.view.match_selector(0, 'source.stylus'): type = 'stylus' 25 | 26 | print(self.view.match_selector(0, 'source.stylus')) 27 | 28 | if type is 'sass' or type is 'stylus': 29 | settings= sublime.load_settings('css_to_sass.sublime-settings') 30 | self.eol = self.detectEol() 31 | self.indent = self.detectIndentation() 32 | self.options['colon'] = ':' if type is 'sass' or settings.get('colon') else '' 33 | self.convert(sublime.get_clipboard(), edit) 34 | else: 35 | self.view.run_command('paste') 36 | 37 | def detectIndentation(self): 38 | indent = self.view.settings().get('tab_size') 39 | tabs = not self.view.settings().get('translate_tabs_to_spaces') 40 | 41 | return '\t' if tabs else indent 42 | 43 | def detectEol(self): 44 | eol_style = self.view.line_endings().lower() 45 | 46 | if (eol_style == 'windows'): eol = '\r\n' 47 | elif (eol_style == 'cr'): eol = '\r' 48 | else: eol = '\n' 49 | 50 | return eol 51 | 52 | def convert(self, text, edit): 53 | if (";" in text): 54 | sublime.set_clipboard(self.process()) 55 | self.view.run_command('paste_and_indent') 56 | 57 | else: 58 | self.view.run_command('paste') 59 | 60 | def process(self): 61 | text = sublime.get_clipboard() 62 | 63 | tree = {'children': {}} 64 | # Remove comments 65 | text = re.sub("\/\*[\s\S]*?\*\/", "", text) 66 | results = re.findall("([^{]+)\{([^}]+)\}", text) 67 | # Process each css block 68 | for (selector, declaration) in results: 69 | selectors = [] 70 | path = tree 71 | selector = selector.strip() 72 | if re.search(",", selector): 73 | path = self.addRule(path, selector) 74 | else: 75 | selector = re.sub("\s*([>\+~])\s*", r' &\1' , selector) 76 | selector = re.sub("(\w)([:\.])", r'\1 &\2' , selector) 77 | selectors = re.split("[\s]+", selector) 78 | for item in selectors: 79 | #fix back special chars 80 | _sel = re.sub("&(.)", r'& \1 ', item) 81 | _sel = re.sub("& ([:\.]) ", r'&\1', _sel) 82 | 83 | path = self.addRule(path, _sel) 84 | for (_property, value) in re.findall("([^:;]+):([^;]+)", declaration): 85 | obj = { 86 | "property": _property.strip(), 87 | "value": value.strip() 88 | } 89 | 90 | path['declarations'].append(obj) 91 | if len(results) == 0: return self.clean(text) 92 | return self.generateOutput(tree) 93 | 94 | 95 | 96 | def addRule(self, path, selector): 97 | if selector in path['children']: 98 | path['children'][selector] = path['children'][selector] 99 | else: 100 | path['children'][selector] = { 'children': {}, 'declarations': [] } 101 | return path['children'][selector] 102 | 103 | def generateOutput(self, tree): 104 | output = '' 105 | openingBracket = self.options['openingBracket'] 106 | for key in tree['children']: 107 | sel = key 108 | output += self.getIndent() + sel + openingBracket + '\n' 109 | self.depth = self.depth + 1 110 | declarations = tree['children'][key]['declarations'] 111 | for index, declaration in enumerate(declarations): 112 | output += self.getIndent() + declaration['property'] + self.options['colon'] + ' ' + declaration['value'] + self.eol 113 | output += self.generateOutput(tree['children'][key]) 114 | self.depth = self.depth - 1 115 | output += self.getIndent() + self.options['closingBracket'] + '\n' + ('$n' if self.depth == 0 else '') 116 | output = re.sub(u'(?imu)^\s*\n', u'', output) 117 | output = re.sub('\$n', '\n', output) 118 | return output 119 | 120 | def getIndent(self): 121 | if self.indent == '\t': 122 | return '\t' * (self.depth + 1) 123 | else: 124 | return ' ' * self.indent * (self.depth + 1) 125 | 126 | def clean(self, text): 127 | print("asdasdas") 128 | if self.options['colon'] == ":": 129 | text = re.sub("(;|{|})", "", text) 130 | else: 131 | text = re.sub("(:|;|{|})", "", text) 132 | return text 133 | -------------------------------------------------------------------------------- /css_to_sass.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "colon": true 3 | } 4 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "install": "messages/install.txt", 3 | "1.1.0": "messages/1.1.0.txt", 4 | "1.2.0": "messages/1.1.0.txt" 5 | } 6 | -------------------------------------------------------------------------------- /messages/1.1.0.txt: -------------------------------------------------------------------------------- 1 | PLEASE UPDATE YOUR CONFIGURATION 2 | 3 | It looked like that until now: 4 | 5 | { 6 | "css_converter_indent": 2, 7 | "css_converter_semicolon": ":", 8 | "css_converter_eol": "", 9 | } 10 | 11 | Now the format looks like this: 12 | 13 | { 14 | "indent": 2, 15 | "colon": true, 16 | "eol": "" 17 | } 18 | 19 | Changes: 20 | 1. There are no prefixes in options. 21 | 2. semicolon is now colon (it was a typo) 22 | 3. colon option has a boolean type (it is enabled or not) 23 | 4. colon option works just for stylus. For sass colon will always be there 24 | -------------------------------------------------------------------------------- /messages/1.2.0.txt: -------------------------------------------------------------------------------- 1 | "indent" and "eol" settings are removed. 2 | Current view settings are used instead. 3 | -------------------------------------------------------------------------------- /messages/install.txt: -------------------------------------------------------------------------------- 1 | Thank you for installing the plugin! 2 | 3 | Please submit an issue on github if you have any ideas to improve the plugin. 4 | https://github.com/lnikell/css-converter/issues 5 | 6 | You can easily configure it with the following settings: 7 | 8 | { 9 | "colon": true 10 | } 11 | 12 | Default hotkey is "ctrl + v", but you could change it to another: 13 | 14 | [ 15 | { "keys": ["ctrl+v"], "command": "css_to_sass" }, 16 | ] 17 | --------------------------------------------------------------------------------