Skip to content

Instantly share code, notes, and snippets.

@vitaLee
Created June 3, 2012 13:26
Show Gist options
  • Save vitaLee/2863474 to your computer and use it in GitHub Desktop.
Save vitaLee/2863474 to your computer and use it in GitHub Desktop.
SublimeText command for compacting/expanding CSS rules
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))
// 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" } },
@vitaLee
Copy link
Author

vitaLee commented Jun 16, 2012

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

Copy link

ghost commented Aug 28, 2012

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!

@haveatry823
Copy link

thanks a lot

@rareyman
Copy link

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!

@vitaLee
Copy link
Author

vitaLee commented Dec 4, 2012

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.

@thiagobousfield
Copy link

Hey bro,

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

Tks.

@vitaLee
Copy link
Author

vitaLee commented Dec 16, 2012

Did you follow the instructions here https://gist.github.com/2863474#file-gistfile1-txt ?

@rareyman
Copy link

@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. :)

@vitaLee
Copy link
Author

vitaLee commented Jan 18, 2013

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

@wwek
Copy link

wwek commented Jan 23, 2013

tks

@wdburgdorf
Copy link

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!

@vitaLee
Copy link
Author

vitaLee commented Mar 22, 2013

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" } }
]

@wdburgdorf
Copy link

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 ...

@wdburgdorf
Copy link

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!

@jhebb
Copy link

jhebb commented Sep 26, 2013

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 + '}')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment