Skip to content

Commit

Permalink
CSS Beautifier ported so far
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Anderson committed Jan 26, 2012
1 parent 9360791 commit 98a4286
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 30 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
HTMLPrettify.pyc
31 changes: 1 addition & 30 deletions README.md
@@ -1,30 +1 @@
# HTML, CSS and Javascript code formatter for Sublime Text editor via node.js
#### [Sublime Text 2](http://www.sublimetext.com/2)
#### [JSBeautifier](http://jsbeautifier.org/)
#### [Node.js download](http://nodejs.org/#download)

## About
This is a Sublime Text 2 plugin and build system allowing you to format your HTML, CSS and JavaScript code. It uses a set of nice beautifier libs made by Einar Lielmanis and Noah Kantrowitz. The formatters are written in JavaScript, so you'll need something (node.js) to interpret JavaScript code outside the browser.

This will work with both HTML, CSS and JavaScript files.

## Installation
First of all, be sure you have [node.js](http://nodejs.org/#download) installed in order to run the beautifier. After you've installed node.js, you will need to setup this plugin.
Each OS has a different `Packages` folder required by Sublime Text. Open it via Preferences -> Browse Packages, and copy this repository contents to the `HTMLPrettify` folder there.

The shorter way of doing this is:
#### Mac
`git clone git://github.com/victorporof/Sublime-HTMLPrettify.git ~/Library/Application\ Support/Sublime\ Text\ 2/Packages/HTMLPrettify`

#### Windows
`git clone git://github.com/victorporof/Sublime-HTMLPrettify.git %APPDATA%\Sublime Text 2\Packages\HTMLPrettify`

## Usage
Open a HTML or JavaScript file, pop out the console in Sublime Text from View -> Show Console, and type `view.run_command("htmlprettify")`.

Writing commands in the console is ugly. Set up your own key combo for this, by going to Preferences -> Key Bindings - Default, and adding a command in that huge array: `{ "keys": ["super+shift+h"], "command": "htmlprettify" }`. You can use any other command you want, thought most of them are already taken.

## Customize
The `HTMLPrettify.py` script has some predefined settings regarding the indentation size, indentation character, maximum chars per line and brace styling. Customize these settings by modifying the script with your desired values (see the [JSBeautifier options](https://github.com/einars/js-beautify/blob/master/beautify-html.js)).

Have fun!
Beginnings of a Python port of [Sublime-HTMLPrettify](https://github.com/victorporof/Sublime-HTMLPrettify).
19 changes: 19 additions & 0 deletions WebBeautify.py
@@ -0,0 +1,19 @@
import commands
import os
import re
import sublime
import sublime_plugin
from .lib import *


class WebBeautifyCommand(sublime_plugin.TextCommand):

def run(self, edit):
self.save()
self.beautify(edit)

def save(self):
self.view.run_command("save")

def prettify(self, edit):
pass
1 change: 1 addition & 0 deletions lib/__init__.py
@@ -0,0 +1 @@
from cssbeautify import css_beautifier
228 changes: 228 additions & 0 deletions lib/cssbeautify.py
@@ -0,0 +1,228 @@
import re
import string


class CssBeautify(object):

def __init__(self):
self.comment = False
self.depth = 0
self.formatted = ''
self.index = 0
self.open_brace_suffix = True
self.options = {
'indent': '\t'
}
self.quote = None
self.state = {
'start': 0,
'at_rule': 1,
'block': 2,
'selector': 3,
'ruleset': 4,
'property': 5,
'separator': 6,
'expression': 7
}

def __call__(self, css, options={}, *args):

self.index = 0
self.formatted = ''

for k, v in self.options.iteritems():
if options[k]:
self.options[k] = options[k]

length = len(css)
state = self.state.start

# Goodbye CRLF
re.sub(r'\r\n', '\n', css)

while self.index < length:
ch = css[self.index]
ch2 = css[self.index + 1]
self.index += 1

# Inside a string literal?
if self.is_quote(self.quote):
self.formatted += ch
if ch == self.quote:
quote = None
if ch == '\\' and ch2 == quote:
# Don't treat escaped character as the closing quote
self.formatted += ch2
self.index += 1
continue

# Starting a string literal?
if self.is_quote(ch):
self.formatted += ch
self.quote = ch
continue

if self.comment:
self.formatted += ch
if ch == '*' and ch2 == '/':
self.comment = False
self.formatted += ch2
self.index += 1
continue
else:
if ch == '/' and ch2 == '*':
self.comment = True
self.formatted += ch
self.formatted += ch2
self.index += 1
continue

if state == self.state.start:

# Copy white spaces and control characters
if ch <= ' ' or ord(ch) >= 128:
state = self.state.start
self.formatted += ch
continue

# Selector or at_rule
if self.is_name(ch) or ch == '@':

# Clear trailing whitespaces and linefeeds
self.formatted.rstrip()

# After finishing a ruleset or directive statement,
# there should be one blank line
if (str[-1] == '}') or str[-1] == ';':
self.formatted = str + '\n\n'
else:
# After block comment, keep all the linfeeds but start
# from the first column (remove whitespaces prefix).
while True:
ch2 = self.formatted[-1]
if ch2 != ' ' and ord(ch2) != 9:
break
self.formatted = self.formatted[0:-1]

self.formatted += ch
state = self.state.at_rule if ch == '@' else self.state.selector
continue

if state == self.state.at_rule:

# ; terminates a statement
if ch == ';':
self.formatted += ch
state = self.state.start
continue

# '{' starts a block
if ch == '{':
self.open_block()
state = self.state.block
continue

self.formatted += ch
continue

if state == self.state.block:
if self.is_name(ch):

# Clear trailing whitespace and linefeeds
str = self.formatted.rstrip()

# Insert blank line if necessary
if str[-1] == '}':
self.formatted = str + '\n\n'
else:
while True:
ch2 = self.formatted[-1]
if ch2 != ' ' and ord(ch2) != 9:
break
self.formatted = self.formatted[0:-1]

self.append_indent()
self.formatted += ch
state = self.state.selector
continue

if ch == '}':
self.close_block()
state = self.state.start
continue

self.formatted += ch
continue

if state = self.state.selector:

# '{' starts the ruleset
if ch == '{':
self.open_block()
state = self.state.ruleset
continue

# '}' resets the state
if ch == '}':
self.close_block()
state = self.state.start
continue

self.formatted += ch
continue

if state == self.state.ruleset:
if ch == '}':
self.close_block()
state = self.state.start
if self.depth > 0:
state = self.state.block
continue

if ch == '\n':
self.formatted += '\n'
continue

if not self.is_whitespace(ch):
self.formatted += '\n'
self.append_indent

self.formatted += ch

def is_name(self, c):
return ch in string.letters or
ch in string.digits or
ch in '-_*.:#'

def is_whitespace(self, c):
return c in string.whitespace

def is_quote(self, c):
return c in '\'"'

def append_indent(self):
self.formatted += (self.options.indent * self.depth)

def open_block(self):
self.formatted = self.formatted.rstrip()

if self.open_brace_suffix:
self.formatted += ' {'
else:
self.formatted += '\n'
self.append_indent
self.formatted += '{'

if ch2 != '\n':
self.formatted += '\n'

self.depth += 1

def close_block(self):
self.depth -= 1
self.formatted = self.formatted.rstrip()
self.formatted += '\n'
self.append_indent()
self.formatted += '}'

css_beautifier = CssBeautify()

2 comments on commit 98a4286

@victorporof
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool!

@csand
Copy link
Owner

@csand csand commented on 98a4286 Jan 29, 2012

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for the comment, Victor. Now I just need to get off my butt and finish the rest of it.

Please sign in to comment.