public
Last active

SublimeText command for compacting/expanding CSS rules

  • Download Gist
compact_expand_css_command.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
import sublime
import sublime_plugin
import re
 
 
class CompactExpandCssCommand(sublime_plugin.TextCommand):
def run(self, edit, action='compact'):
rule_starts = self.view.find_all('\{')
rule_ends = self.view.find_all('\}')
 
rules_regions = list()
regions_to_process = list()
 
selections = self.view.sel()
if len(selections) == 1 and selections[0].empty():
selections = [sublime.Region(0, self.view.size())]
 
for i in range(len(rule_starts)):
rule_region = sublime.Region(rule_starts[i].a, rule_ends[i].b)
rules_regions.append(rule_region)
for sel in selections:
if sel.intersects(rule_region):
regions_to_process.append(rule_region)
break
 
regions_to_process.reverse()
self.process_rules_regions(regions_to_process, action, edit)
 
def process_rules_regions(self, regions, action, edit):
actions = {
'compact': self.compact_rules,
'expand': self.expand_rules,
'toggle': self.toggle_rules
}
actions[action](regions, edit)
 
def toggle_rules(self, regions, edit):
grouped_rules = list()
 
for r in regions:
action_key = 'expand' if self.rule_is_compact(r) else 'compact'
 
if not grouped_rules or not action_key in grouped_rules[-1]:
grouped_rules.append({action_key: []})
 
grouped_rules[-1][action_key].append(r)
 
for group in grouped_rules:
for (action, rules) in group.items():
self.process_rules_regions(rules, action, edit)
 
def compact_rules(self, regions, edit):
view = self.view
 
for collapse_region in regions:
content = view.substr(collapse_region)
 
match = re.match(r"\{([^\}]*)\}", content)
 
rules = match.group(1).split(';')
rules = [r.strip() for r in rules]
rules = '; '.join(rules)
 
view.replace(edit, collapse_region, '{ ' + rules + '}')
 
def expand_rules(self, regions, edit):
view = self.view
 
for expand_region in regions:
content = view.substr(expand_region)
 
match = re.match(r"\{([^\}]*)\}", content)
 
rules = match.group(1).split(';')
rules = filter(lambda r: r.strip(), rules)
rules = ['\t' + r.strip() + ';\n' for r in rules]
rules = ''.join(rules)
 
view.replace(edit, expand_region, '{\n' + rules + '}')
 
def rule_is_compact(self, rule):
return re.match(r"^\{.*\}$", self.view.substr(rule))
gistfile1.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
// commands allow compacting/expanding of selected rules.
// multiple selections are supported
// commands are applied to rules which are covered by selection
// if there's a single empty selection then the command is applied to all rules within the document
 
// 1. save the file above under your Packages/User folder. for more info on where it's located on your platform look here - http://docs.sublimetext.info/en/latest/basic_concepts.html#the-data-directory
// 2.1 add these to Packages/User/Default.sublime-commands to be able to execute through command list
// (if .sublime-commands doesn't exist there just create it by hand)
 
{
"caption": "CSS rules compact",
"command": "compact_expand_css",
"args": { "action": "compact" }
},
{
"caption": "CSS rules expand",
"command": "compact_expand_css",
"args": { "action": "expand" }
},
{
"caption": "CSS rules toggle",
"command": "compact_expand_css",
"args": { "action": "toggle" }
}
 
// or
// 2.2 map commands to keyboard shortcuts in Packages/User/Default(*your OS*).sublime-keymap to take the shortcut (if the file is not present, create by hand or go to Preferences -> Key Bindings - User).
// exmaple what the shortcut might look like
 
{ "keys": ["ctrl+super+]"], "command": "compact_expand_css", "args": { "action": "expand" } },
{ "keys": ["ctrl+super+["], "command": "compact_expand_css", "args": { "action": "compact" } },

updated the explanation a bit.
let me know if you have problems.

Thanks for writing this, it's exactly what I've been looking for.

I'm experiencing an issue, I get the following error when I run either the expand or compact command via the command palette:

Traceback (most recent call last):
File "./sublime_plugin.py", line 356, in run_
File "./compact_expand_css_command.py", line 18, in run
IndexError: list index out of range

Could you please help me understand how to fix this? Thanks!

I am getting the same issue mendoza1984 is experiencing:

Traceback (most recent call last):
File "./sublime_plugin.py", line 356, in run_
File "./CSS-Converter.py", line 19, in run
IndexError: list index out of range

Anyone have any ideas? Thanks!

Sorry i'm late, but there are no gist notifications. :(
Im not using this command that often and wrote it as my first python exercise.
@rareyman are you using less or scss?
The command doesn't account for nested rules and it might delete braces, leaving you with unbalanced braces count.

Hey bro,

I'm new in Sublime and, I can't install, I need more instructions
Can you help me?

Tks.

@vitaLee Yeah, I use LESS and SCSS quite a bit, and that may be part of the issue. One of these days I will roll up my sleeves and see if I can adjust this awesome script to account for LESS and SCSS. :)

@rareman I'll probably take the time to revise this to work with nested rules. Stay tuned

Hi, like thiagobousfield, I followed the instructions, double checked everything, but could not get it to work. The .py file is saved, and I created the commands file. Now what? Where is the "command list"? Under "Tools" I found a "Commands Palette". Is that it? No "CSS rules" there. Do I need to restart something? (I restarted Sublime, but that didn't help.)
Thank you!

Yes @lausianne, the commands should appear in Command Pallet (Tools -> Command Pallete).
If you create the .keymap and .sublime-commands file yourself, make sure to wrap the bindings and commands with [] .

[
{
  "caption": "CSS rules compact",
  "command": "compact_expand_css",
  "args": { "action": "compact" }
},
{
  "caption": "CSS rules expand",
  "command": "compact_expand_css",
  "args": { "action": "expand" }
},
{
  "caption": "CSS rules toggle",
  "command": "compact_expand_css",
  "args": { "action": "toggle" }
}
]

and

[
{ "keys": ["ctrl+super+]"], "command": "compact_expand_css", "args": { "action": "expand" }  },
{ "keys": ["ctrl+super+["], "command": "compact_expand_css", "args": { "action": "compact" } }
]

Thanks, @vitaLee, it was the square brackets that I had not known about. Now it works, very nice. (No restart necessary.)
I'd like to make a small suggestion: The compressed version has spaces before/behind the curly braces, which I like. But there's no space after the colons. Perhaps you might consider adding that.
Selecting all colons manually and adding a space does not work, because it adds spaces before "hover", "active", etc., too ...

Well, done it myself:
Added

rules = rules.replace(': ',':')
rules = rules.replace(':',': ')

after lines 62 and 77. Probably not the most elegant solution, but works for me!

This is awesome, I've been searching all day for a solution for this - comes in super handy for updating older projects.

Did you ever update it for nested rules?

I added the suggestions from @lausianne and also these for my own preference to remove spaces before/after {} when collapsing:

rules = rules.rstrip(' ')

view.replace(edit, collapse_region, '{' + rules + '}')

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.