Sublime Forum

Auto Sort Css Rules

#1

github.com/ajpalkovic/SublimePl … sortCss.py

I’ve always found organizing CSS files to be a pain, and the best trick I’ve had was to always keep my CSS rules in sorted order so they are semi easy/logical to find. But, I hate keeping it ordered.

So, I created a plugin that sorts all of the CSS rules in a file. Additionally, I added a small onSave event, so that every time you save the file it automatically sorts the css rules! That can be disabled by setting sort_css_on_save to false. It is true by default.

Notes:

  1. The new version of the plugin sorts the first continuous block of rules in each selector. This is really only a limitation for scss. If you put css rules after a nested selector, they won’t be sorted.
  2. If you find bugs, please post the css snippet and I’ll fix it.
0 Likes

#2

I’ve encountered the same issue. Seems strange, doesn’t it? :smile:

0 Likes

#3

Yea, I started doing some fancy match, and I could get it to only scroll a couple of lines, I guess I could always write a loop to scroll it one character at a time until it reaches the correct line :smile:

0 Likes

#4

Nice plugin!
There might be a problem though on sorting custom css properties:

filter:alpha(opacity=50);
opacity: 0.5;

or

-moz-border-radius: 5px; border-radius: 5px;

Would be great if these won’t be split like this:

filter:alpha(opacity=50);
padding:0;
opacity: 0.5;

Make sense? There is something that can be done? Thanks!

0 Likes

#5

view.visible_region() is approximate, in the sense that if a line is partially visible, it’ll be included in the visible region. Doing a show() on a partially visible line will scroll the view to reveal the line.

0 Likes

#6

It’s not off by one line though.

If I run this in the console:
sublime.active_window().active_view().show(sublime.active_window().active_view().visible_region())
it scrolls multiple lines.

If I have the top of the buffer at line 1, that scrolls so the top of the buffer is line 35. Running it again moves the buffer to line 52.

0 Likes

#7

@iamntz
-moz- and the other prefixes are stripped when sorting, so that all the properties with the same name but different prefix stay next to each other.

The filter thing could be hard. I think though that isn’t what I want. That starts trying to find a more logical way of grouping stuff. I tried to keep it strictly alphabetically. It’s a slippery slope, one exception leads to another and then its no longer alphabetical.

But, if you really want to, you can certainly modify the plugin. There is a single function self.compareLines I think that does the sort comparison, so you can add exceptions like that if you want to.

0 Likes

#8

Yeah - if a point isn’t fully visible, then show() will attempt to centre the view on that point. This is off the top of my head btw, so I could be wrong.

0 Likes

#9

Yea, that makes sense.

If I do this instead:
sublime.active_window().active_view().show(sublime.active_window().active_view().visible_region().a)
it is definitely better, but it still jumps around in my sortCss.py plugin.

I think the plugin is jumping because the edits force the view to make the edit’d region visible? Maybe there could be an option to disable that behavior? It never jumps on a sorted css file because it doesn’t make any edits.

0 Likes

#10

It turns out that using view.replace() will scroll to reveal the replaced text. It clearly shouldn’t be doing this, and I’ll remove it for the next build.

0 Likes

#11

Thanks, it doesn’t scroll anymore.

I also just pushed an update that enables it work for scss as well. Because of limitations with nested selectors, it is a little limited, but it works in most cases and I’m happy with it. Basically I make the assumption that you will put all the scss rules at the top of a selector and then any nested selectors below it. If you follow that pattern, it will work fine.

0 Likes

#12

Is this working with the latest sublime update for anyone else?

0 Likes

#13

Works for me. You can test it explicitly by binding a key to the sort_css command like this: { “keys”: “ctrl+alt+q”], “command”: “sort_css” }. If it doesn’t work on one file, upload it and I’ll fix it.

0 Likes

#14

Ah yes that works. How might I get this to work on .less files?

0 Likes

#15

It will auto sort .css files on save and .scss now for some reason but not my own hack for .less files. I just copied the .scss rules and added them under.

0 Likes

#16

Yea, you probably can’t copy them exactly for less as the scopes will be different. I have never used less, only css and scss. If you know a good bit about less, then you can try and figure out what the various scopes are and add them, but copying the scss ones probably won’t work.

0 Likes

#17

Cool thanks.

Just a quick question (if you have time, don’t worry if not) am I looking to add all the dict > string names in here ending in .css or .less?

I assume ‘list’ is for property lists and and ‘rules’ if for everything else (‘comment’ is obvious).

raw.github.com/appden/less.tmbu … tmLanguage

e.g. (not complete yet)

  'source.css.less': {
    'list': 
      'meta.property-list.css',    
      'support.type.property-name.css',    
      'support.function.less'
    ],
    'rules': 
      'meta.property-name.css', 'meta.property-value.css'],
      'support.function.less', 'variable.other.less', 'keyword.operator.less']
    ],
    'ignore': 
      'comment.block.css',
      'comment.line.double-slash.less'
    ]
0 Likes

#18

Yea the basic idea is that ‘lists’ define the regions to sort, so like #id { rule1; rule2; }, the scopes in list should match the entire thing (between the curly braces). Inside of that region, it needs to identify individual rules. So, each array in rules is a sequence of scopes to match. In your example, it will essentially attempt to match it like this:
[whitespace or any scopes in the ‘ignore’ section]{0 or more times}[meta.property-name.css]{1 or more times}[whitespace or any scopes in the ‘ignore’ section]{0 or more times}[meta.property-value.css]{1 or more times}

With nested regions, it gets much more complicated because the scopes don’t understand nesting, which is fine, but problematic. The plugin works for nesting, but only if all of the rules are listed before any nesting is done.

#id { rule1; rule2; #id2 { nestedRule1; nestedRule2; } rule3;} would only sort rule1 &rule2, and nestedRule1 & 2. rule3 can’t be easily sorted without bracket matching.

0 Likes

#19

Would it be possible for this to be updated so that it supports inline block comments?
Right now all the CSS I work with is using inline block comments, so the sorting algorithm always ends up moving them elsewhere.
For example, the code below

div.class {
    height:         189px;
    position:       relative;
    z-index:        20; /*above main and content */
    margin-bottom:  -6px;
}

becomes this after being sorted.

div.class {
    height:         189px; /*above main and content */
    margin-bottom:  -6px;
    position:       relative;
    z-index:        20;
}

The comment jumped from z-index to height because it was “above” margin-bottom so it was assumed to be a comment related to it.
A condition checking if the comment is the only text on the line would fix this I think.
So if the line above is only a comment, move it with the line below. If it isn’t, keep it with the current line.
I don’t know Python so I’m not sure if that would be hard to do or not, but hopefully it wouldn’t be too hard.

Other than that, this plugin is great! I always get annoyed with my co-workers lack of organization with things like CSS files and this saves me loads of time. :smiley: Thanks for all your hard work!

0 Likes

#20

Is the plugin still working in the latest ST for anyone? It’s stopped working for me.

0 Likes