Skip to content

Commit

Permalink
initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
du-song committed Jan 2, 2012
0 parents commit fb54a34
Show file tree
Hide file tree
Showing 16 changed files with 2,889 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.pyc
*.cache
*.sublime-project
.DS_Store
30 changes: 30 additions & 0 deletions FormatSQL.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import sublime
import sublime_plugin
import re
from os.path import basename
import sqlparse

class FormatSqlCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
regions = view.sel()
# if there are more than 1 region or region one and it's not empty
if len(regions) > 1 or not regions[0].empty():
for region in view.sel():
if not region.empty():
s = view.substr(region)
s = self._run(s)
view.replace(edit, region, s)
else: #format all text
alltextreg = sublime.Region(0, view.size())
s = view.substr(alltextreg)
s = self._run(s)
view.replace(edit, alltextreg, s)

def _run(self, s):
settings = self.view.settings()
#indent_char = " " if settings.get("translate_tabs_to_spaces") else "\t"
indent_char = " " #TODO indent by TAB (currently not supported in python-sqlparse)
indent_size = int(settings.get("tab_size")) if indent_char == " " else 1
s = s.encode("utf-8")
return sqlparse.format(s, keyword_case="upper", reindent=True, indent_width=indent_size)
1 change: 1 addition & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python-sqlparse and this code is on 2-clauses BSD http://www.opensource.org/licenses/bsd-license.php
20 changes: 20 additions & 0 deletions Main.sublime-menu
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[
{
"id": "selection",
"caption": "Selection",
"children":
[
{
"id": "format",
"caption": "Format",
"children":
[
{
"caption": "Format SQL Statement",
"command": "format_sql"
}
]
}
]
}
]
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Summary

FormatSQL formats long SQL statement to a more readable form by using [python-sqlparse library](http://code.google.com/p/python-sqlparse/).


## How to Use

select sql and click menu Selection -> Format -> SQL


### Configure key binding

add the following line to keymap settings

{ "keys": ["super+k", "super+s"], "command": "format_sql" },


## License

[python-sqlparse library](http://code.google.com/p/python-sqlparse/) and this code are both on [2-clauses BSD](http://www.opensource.org/licenses/bsd-license.php)
61 changes: 61 additions & 0 deletions sqlparse/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com
#
# This module is part of python-sqlparse and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php.

"""Parse SQL statements."""


__version__ = '0.1.3'


class SQLParseError(Exception):
"""Base class for exceptions in this module."""


# Setup namespace
from sqlparse import engine
from sqlparse import filters
from sqlparse import formatter


def parse(sql):
"""Parse sql and return a list of statements.
*sql* is a single string containting one or more SQL statements.
Returns a tuple of :class:`~sqlparse.sql.Statement` instances.
"""
stack = engine.FilterStack()
stack.full_analyze()
return tuple(stack.run(sql))


def format(sql, **options):
"""Format *sql* according to *options*.
Available options are documented in :ref:`formatting`.
Returns the formatted SQL statement as string.
"""
stack = engine.FilterStack()
options = formatter.validate_options(options)
stack = formatter.build_filter_stack(stack, options)
stack.postprocess.append(filters.SerializerUnicode())
return ''.join(stack.run(sql))


def split(sql):
"""Split *sql* into single statements.
Returns a list of strings.
"""
stack = engine.FilterStack()
stack.split_statements = True
return [unicode(stmt) for stmt in stack.run(sql)]


from sqlparse.engine.filter import StatementFilter
def split2(stream):
splitter = StatementFilter()
return list(splitter.process(None, stream))
80 changes: 80 additions & 0 deletions sqlparse/engine/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright (C) 2008 Andi Albrecht, albrecht.andi@gmail.com
#
# This module is part of python-sqlparse and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php.

"""filter"""

from sqlparse import lexer
from sqlparse.engine import grouping
from sqlparse.engine.filter import StatementFilter

# XXX remove this when cleanup is complete
Filter = object


class FilterStack(object):

def __init__(self):
self.preprocess = []
self.stmtprocess = []
self.postprocess = []
self.split_statements = False
self._grouping = False

def _flatten(self, stream):
for token in stream:
if token.is_group():
for t in self._flatten(token.tokens):
yield t
else:
yield token

def enable_grouping(self):
self._grouping = True

def full_analyze(self):
self.enable_grouping()

def run(self, sql):
stream = lexer.tokenize(sql)
# Process token stream
if self.preprocess:
for filter_ in self.preprocess:
stream = filter_.process(self, stream)

if (self.stmtprocess or self.postprocess or self.split_statements
or self._grouping):
splitter = StatementFilter()
stream = splitter.process(self, stream)

if self._grouping:

def _group(stream):
for stmt in stream:
grouping.group(stmt)
yield stmt
stream = _group(stream)

if self.stmtprocess:

def _run1(stream):
ret = []
for stmt in stream:
for filter_ in self.stmtprocess:
filter_.process(self, stmt)
ret.append(stmt)
return ret
stream = _run1(stream)

if self.postprocess:

def _run2(stream):
for stmt in stream:
stmt.tokens = list(self._flatten(stmt.tokens))
for filter_ in self.postprocess:
stmt = filter_.process(self, stmt)
yield stmt
stream = _run2(stream)

return stream
105 changes: 105 additions & 0 deletions sqlparse/engine/filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-

from sqlparse.sql import Statement, Token
from sqlparse import tokens as T


class TokenFilter(object):

def __init__(self, **options):
self.options = options

def process(self, stack, stream):
"""Process token stream."""
raise NotImplementedError


class StatementFilter(TokenFilter):

def __init__(self):
TokenFilter.__init__(self)
self._in_declare = False
self._in_dbldollar = False
self._is_create = False
self._begin_depth = 0

def _reset(self):
self._in_declare = False
self._in_dbldollar = False
self._is_create = False
self._begin_depth = 0

def _change_splitlevel(self, ttype, value):
# PostgreSQL
if (ttype == T.Name.Builtin
and value.startswith('$') and value.endswith('$')):
if self._in_dbldollar:
self._in_dbldollar = False
return -1
else:
self._in_dbldollar = True
return 1
elif self._in_dbldollar:
return 0

# ANSI
if ttype not in T.Keyword:
return 0

unified = value.upper()

if unified == 'DECLARE' and self._is_create:
self._in_declare = True
return 1

if unified == 'BEGIN':
self._begin_depth += 1
if self._in_declare: # FIXME(andi): This makes no sense.
return 0
return 0

if unified == 'END':
# Should this respect a preceeding BEGIN?
# In CASE ... WHEN ... END this results in a split level -1.
self._begin_depth = max(0, self._begin_depth - 1)
return -1

if ttype is T.Keyword.DDL and unified.startswith('CREATE'):
self._is_create = True
return 0

if (unified in ('IF', 'FOR')
and self._is_create and self._begin_depth > 0):
return 1

# Default
return 0

def process(self, stack, stream):
splitlevel = 0
stmt = None
consume_ws = False
stmt_tokens = []
for ttype, value in stream:
# Before appending the token
if (consume_ws and ttype is not T.Whitespace
and ttype is not T.Comment.Single):
consume_ws = False
stmt.tokens = stmt_tokens
yield stmt
self._reset()
stmt = None
splitlevel = 0
if stmt is None:
stmt = Statement()
stmt_tokens = []
splitlevel += self._change_splitlevel(ttype, value)
# Append the token
stmt_tokens.append(Token(ttype, value))
# After appending the token
if (splitlevel <= 0 and ttype is T.Punctuation
and value == ';'):
consume_ws = True
if stmt is not None:
stmt.tokens = stmt_tokens
yield stmt
Loading

0 comments on commit fb54a34

Please sign in to comment.