1、CSS自动完成文件
将下面的保存为 CSS.ACP,然后在设置里面指定即可,我只加了自己常用的一些属性,你可以自行扩展。
; EditPlus Auto - completion file v1.0 written by matin0728@gmail.com, QQ 5364241 沙加 - 博客园
; This file is provided as a default auto - completion file for Java and C # .
# CASE=y
# T=b
background: ^ !;
# T=bi
background - image: ^ !;
# T=bp
background - position " ^!;
# T=bc
background - color: ^ !;
# T=fl
float:left;
# T=fr
float:right;
# T=of
overflow:hidden;
# T=z
zoom: 1 ;
# T=d
display: ^ !;
# T=db
display:block;
# T=dn
display:none;
# T=fw
font - weight: ^ !;
# T=fs
font - size: ^ !;
# T=h
height: ^ !;
# T=w
width: ^ !;
# T=lh
line - height: ^ !;
# T=c
color: ^ !;
# T=fs
font - size: ^ !;
# T=p
padding: ^ !;
# T=pt
padding - top: ^ !;
# T=pb
padding - bottom: ^ !;
# T=pl
padding - left: ^ !;
# T=pr
padding - right: ^ !;
# T=m
margin: ^ !;
# T=mt
margin - top: ^ !;
# T=ml
margin - left: ^ !;
# T=mr
margin - right: ^ !;
# T=mb
margin - bottom: ^ !;
# T=rbt
- moz - border - radius - topleft:5px; - moz - border - radius - topright:5px; - webkit - border - radius - topleft:5px; - webkit - border - radius - topright:5px;
# T=rbb
- moz - border - radius - bottomleft:5px; - moz - border - radius - bottomright:5px; - webkit - border - radius - bottomleft:5px; - webkit - border - radius - bottomright:5px;
# T=rb
- moz - border - radius:5px; - webkit - border - radius:5px;
# T=ta
text - align: ^ !;
# T=tal
text - align:left;
# T=tar
text - align:right;
# T=tac
text - align:center;
# T=ti
text - indent: ^ !;
# T=v
visibility:hidden;
# T=ps
position: ^ !;
# T=psr
position:relative;
# T=psa
position:absolute;
#
2、Sparkup 的Editplus 移植版
如果你不知道 Sparkup 用来做什么,可以去看看 Zencoding
使用这个工具需要本机安装Python的执行环境,注意还需要修改环境变量把python.exe的目录加到PATH里面去,并导入win32的剪帖板包,具体可以看这里
相对于原始的那个 sparkup, 我略作了修改,好让它在console 里面使用参数调用,将下面这个保存到 spark.py 文件
# -*- coding: utf-8 -*-
version = " 0.1.3 "
import os
import fileinput
import getopt
import sys
import re
import win32clipboard, win32con
# ===============================================================================
class Dialect:
shortcuts = {}
synonyms = {}
required = {}
short_tags = ()
class HtmlDialect(Dialect):
shortcuts = {
' cc:ie ' : {
' opening_tag ' : ' <!--[if IE]> ' ,
' closing_tag ' : ' <![endif]--> ' },
' cc:ie6 ' : {
' opening_tag ' : ' <!--[if lte IE 6]> ' ,
' closing_tag ' : ' <![endif]--> ' },
' cc:ie7 ' : {
' opening_tag ' : ' <!--[if lte IE 7]> ' ,
' closing_tag ' : ' <![endif]--> ' },
' cc:noie ' : {
' opening_tag ' : ' <!--[if !IE]><!--> ' ,
' closing_tag ' : ' <!--<![endif]--> ' },
' html:4t ' : {
' expand ' : True,
' opening_tag ' :
' <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n ' +
' <html lang="en">\n ' +
' <head>\n ' +
' ' + ' <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />\n ' +
' ' + ' <title></title>\n ' +
' </head>\n ' +
' <body> ' ,
' closing_tag ' :
' </body>\n ' +
' </html> ' },
' html:4s ' : {
' expand ' : True,
' opening_tag ' :
' <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n ' +
' <html lang="en">\n ' +
' <head>\n ' +
' ' + ' <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />\n ' +
' ' + ' <title></title>\n ' +
' </head>\n ' +
' <body> ' ,
' closing_tag ' :
' </body>\n ' +
' </html> ' },
' html:xt ' : {
' expand ' : True,
' opening_tag ' :
' <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n ' +
' <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\n ' +
' <head>\n ' +
' ' + ' <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />\n ' +
' ' + ' <title></title>\n ' +
' </head>\n ' +
' <body> ' ,
' closing_tag ' :
' </body>\n ' +
' </html> ' },
' html:xs ' : {
' expand ' : True,
' opening_tag ' :
' <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n ' +
' <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\n ' +
' <head>\n ' +
' ' + ' <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />\n ' +
' ' + ' <title></title>\n ' +
' </head>\n ' +
' <body> ' ,
' closing_tag ' :
' </body>\n ' +
' </html> ' },
' html:xxs ' : {
' expand ' : True,
' opening_tag ' :
' <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n ' +
' <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\n ' +
' <head>\n ' +
' ' + ' <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />\n ' +
' ' + ' <title></title>\n ' +
' </head>\n ' +
' <body> ' ,
' closing_tag ' :
' </body>\n ' +
' </html> ' },
' html:5 ' : {
' expand ' : True,
' opening_tag ' :
' <!DOCTYPE html>\n ' +
' <html lang="en">\n ' +
' <head>\n ' +
' ' + ' <meta charset="UTF-8" />\n ' +
' ' + ' <title></title>\n ' +
' </head>\n ' +
' <body> ' ,
' closing_tag ' :
' </body>\n ' +
' </html> ' },
' input:button ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' button ' , ' type ' : ' button ' , ' name ' : '' , ' value ' : '' }
},
' input:password ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' text password ' , ' type ' : ' password ' , ' name ' : '' , ' value ' : '' }
},
' input:radio ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' radio ' , ' type ' : ' radio ' , ' name ' : '' , ' value ' : '' }
},
' input:checkbox ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' checkbox ' , ' type ' : ' checkbox ' , ' name ' : '' , ' value ' : '' }
},
' input:file ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' file ' , ' type ' : ' file ' , ' name ' : '' , ' value ' : '' }
},
' input:text ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' text ' , ' type ' : ' text ' , ' name ' : '' , ' value ' : '' }
},
' input:submit ' : {
' name ' : ' input ' ,
' attributes ' : { ' class ' : ' submit ' , ' type ' : ' submit ' , ' value ' : '' }
},
' input:hidden ' : {
' name ' : ' input ' ,
' attributes ' : { ' type ' : ' hidden ' , ' name ' : '' , ' value ' : '' }
},
' script:src ' : {
' name ' : ' script ' ,
' attributes ' : { ' src ' : '' }
},
' script:jquery ' : {
' name ' : ' script ' ,
' attributes ' : { ' src ' : ' http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js ' }
},
' script:jsapi ' : {
' name ' : ' script ' ,
' attributes ' : { ' src ' : ' http://www.google.com/jsapi ' }
},
' script:jsapix ' : {
' name ' : ' script ' ,
' text ' : ' \n google.load("jquery", "1.3.2");\n google.setOnLoadCallback(function() {\n \n });\n '
},
' link:css ' : {
' name ' : ' link ' ,
' attributes ' : { ' rel ' : ' stylesheet ' , ' type ' : ' text/css ' , ' href ' : '' , ' media ' : ' all ' },
},
' link:print ' : {
' name ' : ' link ' ,
' attributes ' : { ' rel ' : ' stylesheet ' , ' type ' : ' text/css ' , ' href ' : '' , ' media ' : ' print ' },
},
' link:favicon ' : {
' name ' : ' link ' ,
' attributes ' : { ' rel ' : ' shortcut icon ' , ' type ' : ' image/x-icon ' , ' href ' : '' },
},
' link:touch ' : {
' name ' : ' link ' ,
' attributes ' : { ' rel ' : ' apple-touch-icon ' , ' href ' : '' },
},
' link:rss ' : {
' name ' : ' link ' ,
' attributes ' : { ' rel ' : ' alternate ' , ' type ' : ' application/rss+xml ' , ' title ' : ' RSS ' , ' href ' : '' },
},
' link:atom ' : {
' name ' : ' link ' ,
' attributes ' : { ' rel ' : ' alternate ' , ' type ' : ' application/atom+xml ' , ' title ' : ' Atom ' , ' href ' : '' },
},
' meta:ie7 ' : {
' name ' : ' meta ' ,
' attributes ' : { ' http-equiv ' : ' X-UA-Compatible ' , ' content ' : ' IE=7 ' },
},
' meta:ie8 ' : {
' name ' : ' meta ' ,
' attributes ' : { ' http-equiv ' : ' X-UA-Compatible ' , ' content ' : ' IE=8 ' },
},
' form:get ' : {
' name ' : ' form ' ,
' attributes ' : { ' method ' : ' get ' },
},
' form:g ' : {
' name ' : ' form ' ,
' attributes ' : { ' method ' : ' get ' },
},
' form:post ' : {
' name ' : ' form ' ,
' attributes ' : { ' method ' : ' post ' },
},
' form:p ' : {
' name ' : ' form ' ,
' attributes ' : { ' method ' : ' post ' },
},
}
synonyms = {
' checkbox ' : ' input:checkbox ' ,
' check ' : ' input:checkbox ' ,
' input:c ' : ' input:checkbox ' ,
' button ' : ' input:button ' ,
' input:b ' : ' input:button ' ,
' input:h ' : ' input:hidden ' ,
' hidden ' : ' input:hidden ' ,
' submit ' : ' input:submit ' ,
' input:s ' : ' input:submit ' ,
' radio ' : ' input:radio ' ,
' input:r ' : ' input:radio ' ,
' text ' : ' input:text ' ,
' passwd ' : ' input:password ' ,
' password ' : ' input:password ' ,
' pw ' : ' input:password ' ,
' input:t ' : ' input:text ' ,
' linkcss ' : ' link:css ' ,
' scriptsrc ' : ' script:src ' ,
' jquery ' : ' script:jquery ' ,
' jsapi ' : ' script:jsapi ' ,
' html5 ' : ' html:5 ' ,
' html4 ' : ' html:4s ' ,
' html4s ' : ' html:4s ' ,
' html4t ' : ' html:4t ' ,
' xhtml ' : ' html:xxs ' ,
' xhtmlt ' : ' html:xt ' ,
' xhtmls ' : ' html:xs ' ,
' xhtml11 ' : ' html:xxs ' ,
' opt ' : ' option ' ,
' st ' : ' strong ' ,
' css ' : ' style ' ,
' csss ' : ' link:css ' ,
' css:src ' : ' link:css ' ,
' csssrc ' : ' link:css ' ,
' js ' : ' script ' ,
' jss ' : ' script:src ' ,
' js:src ' : ' script:src ' ,
' jssrc ' : ' script:src ' ,
}
short_tags = (
' area ' , ' base ' , ' basefont ' , ' br ' , ' embed ' , ' hr ' , \
' input ' , ' img ' , ' link ' , ' param ' , ' meta ' )
required = {
' a ' : { ' href ' : '' },
' base ' : { ' href ' : '' },
' abbr ' : { ' title ' : '' },
' acronym ' :{ ' title ' : '' },
' bdo ' : { ' dir ' : '' },
' link ' : { ' rel ' : ' stylesheet ' , ' href ' : '' },
' style ' : { ' type ' : ' text/css ' },
' script ' : { ' type ' : ' text/javascript ' },
' img ' : { ' src ' : '' , ' alt ' : '' },
' iframe ' : { ' src ' : '' , ' frameborder ' : ' 0 ' },
' embed ' : { ' src ' : '' , ' type ' : '' },
' object ' : { ' data ' : '' , ' type ' : '' },
' param ' : { ' name ' : '' , ' value ' : '' },
' form ' : { ' action ' : '' , ' method ' : ' post ' },
' table ' : { ' cellspacing ' : ' 0 ' },
' input ' : { ' type ' : '' , ' name ' : '' , ' value ' : '' },
' base ' : { ' href ' : '' },
' area ' : { ' shape ' : '' , ' coords ' : '' , ' href ' : '' , ' alt ' : '' },
' select ' : { ' name ' : '' },
' option ' : { ' value ' : '' },
' textarea ' :{ ' name ' : '' },
' meta ' : { ' content ' : '' },
}
class Parser:
""" The parser.
"""
# Constructor
# ---------------------------------------------------------------------------
def __init__ (self, options = None, str = '' , dialect = HtmlDialect()):
""" Constructor.
"""
self.tokens = []
self.str = str
self.options = options
self.dialect = dialect
self.root = Element(parser = self)
self.caret = []
self.caret.append(self.root)
self._last = []
# Methods
# ---------------------------------------------------------------------------
def load_string(self, str):
""" Loads a string to parse.
"""
self.str = str
self._tokenize()
self._parse()
def render(self):
""" Renders.
Called by [[Router]].
"""
# Get the initial render of the root node
output = self.root.render()
# Indent by whatever the input is indented with
indent = re.findall( " ^[\r\n]*(\s*) " , self.str)[0]
output = indent + output.replace( " \n " , " \n " + indent)
# Strip newline if not needed
if self.options.has( " no-last-newline " ) \
or self.prefix or self.suffix:
output = re.sub(r ' \n\s*$ ' , '' , output)
# TextMate mode
if self.options.has( " textmate " ):
output = self._textmatify(output)
return output
# Protected methods
# ---------------------------------------------------------------------------
def _textmatify(self, output):
""" Returns a version of the output with TextMate placeholders in it.
"""
matches = re.findall(r ' (></)|("")|(\n\s+)\n|(.|\s) ' , output)
output = ''
n = 1
for i in matches:
if i[0]:
output += ' >$%i</ ' % n
n += 1
elif i[ 1 ]:
output += ' "$%i" ' % n
n += 1
elif i[ 2 ]:
output += i[ 2 ] + ' $%i\n ' % n
n += 1
elif i[ 3 ]:
output += i[ 3 ]
output += " $0 "
return output
def _tokenize(self):
""" Tokenizes.
Initializes [[self.tokens]].
"""
str = self.str.strip()
# Find prefix/suffix
while True:
match = re.match(r " ^(\s*<[^>]+>\s*) " , str)
if match is None: break
if self.prefix is None: self.prefix = ''
self.prefix += match.group(0)
str = str[len(match.group(0)):]
while True:
match = re.findall(r " (\s*<[^>]+>[\s\n\r]*)$ " , str)
if not match: break
if self.suffix is None: self.suffix = ''
self.suffix = match[0] + self.suffix
str = str[: - len(match[0])]
# Split by the element separators
for token in re.split( ' (<|>|\+(?!\\s*\+|$)) ' , str):
if token.strip() != '' :
self.tokens.append(Token(token, parser = self))
def _parse(self):
""" Takes the tokens and does its thing.
Populates [[self.root]].
"""
# Carry it over to the root node.
if self.prefix or self.suffix:
self.root.prefix = self.prefix
self.root.suffix = self.suffix
self.root.depth += 1
for token in self.tokens:
if token.type == Token.ELEMENT:
# Reset the "last elements added" list. We will
# repopulate this with the new elements added now.
self._last[:] = []
# Create [[Element]]s from a [[Token]].
# They will be created as many as the multiplier specifies,
# multiplied by how many carets we have
count = 0
for caret in self.caret:
local_count = 0
for i in range(token.multiplier):
count += 1
local_count += 1
new = Element(token, caret,
count = count,
local_count = local_count,
parser = self)
self._last.append(new)
caret.append(new)
# For >
elif token.type == Token.CHILD:
# The last children added.
self.caret[:] = self._last
# For <
elif token.type == Token.PARENT:
# If we're the root node, don't do anything
parent = self.caret[0].parent
if parent is not None:
self.caret[:] = [parent]
return
# Properties
# ---------------------------------------------------------------------------
# Property: dialect
# The dialect of XML
dialect = None
# Property: str
# The string
str = ''
# Property: tokens
# The list of tokens
tokens = []
# Property: options
# Reference to the [[Options]] instance
options = None
# Property: root
# The root [[Element]] node.
root = None
# Property: caret
# The current insertion point.
caret = None
# Property: _last
# List of the last appended stuff
_last = None
# Property: indent
# Yeah
indent = ''
# Property: prefix
# (String) The trailing tag in the beginning.
#
# Description:
# For instance, in `<div>ul>li</div>`, the `prefix` is `<div>`.
prefix = ''
# Property: suffix
# (string) The trailing tag at the end.
suffix = ''
pass
# ===============================================================================
class Element:
""" An element.
"""
def __init__ (self, token = None, parent = None, count = None, local_count = None, \
parser = None, opening_tag = None, closing_tag = None, \
attributes = None, name = None, text = None):
""" Constructor.
This is called by ???.
Description:
All parameters are optional.
token - (Token) The token (required)
parent - (Element) Parent element; `None` if root
count - (Int) The number to substitute for `&` (e.g., in `li.item-$`)
local_count - (Int) The number to substitute for `$` (e.g., in `li.item-&`)
parser - (Parser) The parser
attributes - ...
name - ...
text - ...
"""
self.children = []
self.attributes = {}
self.parser = parser
if token is not None:
# Assumption is that token is of type [[Token]] and is
# a [[Token.ELEMENT]].
self.name = token.name
self.attributes = token.attributes.copy()
self.text = token.text
self.populate = token.populate
self.expand = token.expand
self.opening_tag = token.opening_tag
self.closing_tag = token.closing_tag
# `count` can be given. This will substitude & in classname and ID
if count is not None:
for key in self.attributes:
attrib = self.attributes[key]
attrib = attrib.replace( ' & ' , ( " %i " % count))
if local_count is not None:
attrib = attrib.replace( ' $ ' , ( " %i " % local_count))
self.attributes[key] = attrib
# Copy over from parameters
if attributes: self.attributes = attribues
if name: self.name = name
if text: self.text = text
self._fill_attributes()
self.parent = parent
if parent is not None:
self.depth = parent.depth + 1
if self.populate: self._populate()
def render(self):
""" Renders the element, along with it's subelements, into HTML code.
[Grouped under "Rendering methods"]
"""
output = ""
try : spaces_count = int(self.parser.options.options[ ' indent-spaces ' ])
except : spaces_count = 4
spaces = ' ' * spaces_count
indent = self.depth * spaces
prefix, suffix = ( '' , '' )
if self.prefix: prefix = self.prefix + " \n "
if self.suffix: suffix = self.suffix
# Make the guide from the ID (/#header), or the class if there's no ID (/.item)
# This is for the start-guide, end-guide and post-tag-guides
guide_str = ''
if ' id ' in self.attributes:
guide_str += " #%s " % self.attributes[ ' id ' ]
elif ' class ' in self.attributes:
guide_str += " .%s " % self.attributes[ ' class ' ].replace( ' ' , ' . ' )
# Build the post-tag guide (e.g., </div><!-- /#header -->),
# the start guide, and the end guide.
guide = ''
start_guide = ''
end_guide = ''
if ((self.name == ' div ' ) and \
(( ' id ' in self.attributes) or ( ' class ' in self.attributes))):
if (self.parser.options.has( ' post-tag-guides ' )):
guide = " <!-- /%s --> " % guide_str
if (self.parser.options.has( ' start-guide-format ' )):
format = self.parser.options.get( ' start-guide-format ' )
try : start_guide = format % guide_str
except : start_guide = (format + " " + guide_str).strip()
start_guide = " %s<!-- %s -->\n " % (indent, start_guide)
if (self.parser.options.has( ' end-guide-format ' )):
format = self.parser.options.get( ' end-guide-format ' )
try : end_guide = format % guide_str
except : end_guide = (format + " " + guide_str).strip()
end_guide = " \n%s<!-- %s --> " % (indent, end_guide)
# Short, self-closing tags (<br />)
short_tags = self.parser.dialect.short_tags
# When it should be expanded..
# (That is, <div>\n...\n</div> or similar -- wherein something must go
# inside the opening/closing tags)
if len(self.children) > 0 \
or self.expand \
or prefix or suffix \
or (self.parser.options.has( ' expand-divs ' ) and self.name == ' div ' ):
for child in self.children:
output += child.render()
# For expand divs: if there are no children (that is, `output`
# is still blank despite above), fill it with a blank line.
if (output == '' ): output = indent + spaces + " \n "
# If we're a root node and we have a prefix or suffix...
# (Only the root node can have a prefix or suffix.)
if prefix or suffix:
output = " %s%s%s%s%s\n " % \
(indent, prefix, output, suffix, guide)
# Uh..
elif self.name != '' or \
self.opening_tag is not None or \
self.closing_tag is not None:
output = start_guide + \
indent + self.get_opening_tag() + " \n " + \
output + \
indent + self.get_closing_tag() + \
guide + end_guide + " \n "
# Short, self-closing tags (<br />)
elif self.name in short_tags:
output = " %s<%s />\n " % (indent, self.get_default_tag())
# Tags with text, possibly
elif self.name != '' or \
self.opening_tag is not None or \
self.closing_tag is not None:
output = " %s%s%s%s%s%s%s%s " % \
(start_guide, indent, self.get_opening_tag(), \
self.text, \
self.get_closing_tag(), \
guide, end_guide, " \n " )
# Else, it's an empty-named element (like the root). Pass.
else : pass
return output
def get_default_tag(self):
""" Returns the opening tag (without brackets).
Usage:
element.get_default_tag()
[Grouped under "Rendering methods"]
"""
output = ' %s ' % (self.name)
for key, value in self.attributes.iteritems():
output += ' %s="%s" ' % (key, value)
return output
def get_opening_tag(self):
if self.opening_tag is None:
return " <%s> " % self.get_default_tag()
else :
return self.opening_tag
def get_closing_tag(self):
if self.closing_tag is None:
return " </%s> " % self.name
else :
return self.closing_tag
def append(self, object):
""" Registers an element as a child of this element.
Usage:
element.append(child)
Description:
Adds a given element `child` to the children list of this element. It
will be rendered when [[render()]] is called on the element.
See also:
- [[get_last_child()]]
[Grouped under "Traversion methods"]
"""
self.children.append(object)
def get_last_child(self):
""" Returns the last child element which was [[append()]]ed to this element.
Usage:
element.get_last_child()
Description:
This is the same as using `element.children[-1]`.
[Grouped under "Traversion methods"]
"""
return self.children[ - 1 ]
def _populate(self):
""" Expands with default items.
This is called when the [[populate]] flag is turned on.
"""
if self.name == ' ul ' :
elements = [Element(name = ' li ' , parent = self, parser = self.parser)]
elif self.name == ' dl ' :
elements = [
Element(name = ' dt ' , parent = self, parser = self.parser),
Element(name = ' dd ' , parent = self, parser = self.parser)]
elif self.name == ' table ' :
tr = Element(name = ' tr ' , parent = self, parser = self.parser)
td = Element(name = ' td ' , parent = tr, parser = self.parser)
tr.children.append(td)
elements = [tr]
else :
elements = []
for el in elements:
self.children.append(el)
def _fill_attributes(self):
""" Fills default attributes for certain elements.
Description:
This is called by the constructor.
[Protected, grouped under "Protected methods"]
"""
# Make sure <a>'s have a href, <img>'s have an src, etc.
required = self.parser.dialect.required
for element, attribs in required.iteritems():
if self.name == element:
for attrib in attribs:
if attrib not in self.attributes:
self.attributes[attrib] = attribs[attrib]
# ---------------------------------------------------------------------------
# Property: last_child
# [Read-only]
last_child = property(get_last_child)
# ---------------------------------------------------------------------------
# Property: parent
# (Element) The parent element.
parent = None
# Property: name
# (String) The name of the element (e.g., `div`)
name = ''
# Property: attributes
# (Dict) The dictionary of attributes (e.g., `{'src': 'image.jpg'}`)
attributes = None
# Property: children
# (List of Elements) The children
children = None
# Property: opening_tag
# (String or None) The opening tag. Optional; will use `name` and
# `attributes` if this is not given.
opening_tag = None
# Property: closing_tag
# (String or None) The closing tag
closing_tag = None
text = ''
depth = - 1
expand = False
populate = False
parser = None
# Property: prefix
# Only the root note can have this.
prefix = None
suffix = None
# ===============================================================================
class Token:
def __init__ (self, str, parser = None):
""" Token.
Description:
str - The string to parse
In the string `div > ul`, there are 3 tokens. (`div`, `>`, and `ul`)
For `>`, it will be a `Token` with `type` set to `Token.CHILD`
"""
self.str = str.strip()
self.attributes = {}
self.parser = parser
# Set the type.
if self.str == ' < ' :
self.type = Token.PARENT
elif self.str == ' > ' :
self.type = Token.CHILD
elif self.str == ' + ' :
self.type = Token.SIBLING
else :
self.type = Token.ELEMENT
self._init_element()
def _init_element(self):
""" Initializes. Only called if the token is an element token.
[Private]
"""
# Get the tag name. Default to DIV if none given.
name = re.findall( ' ^([\w\-:]*) ' , self.str)[0]
name = name.lower().replace( ' - ' , ' : ' )
# Find synonyms through this thesaurus
synonyms = self.parser.dialect.synonyms
if name in synonyms.keys():
name = synonyms[name]
if ' : ' in name:
try : spaces_count = int(self.parser.options.get( ' indent-spaces ' ))
except : spaces_count = 4
indent = ' ' * spaces_count
shortcuts = self.parser.dialect.shortcuts
if name in shortcuts.keys():
for key, value in shortcuts[name].iteritems():
setattr(self, key, value)
if ' html ' in name:
return
else :
self.name = name
elif (name == '' ): self.name = ' div '
else : self.name = name
# Look for attributes
attribs = []
for attrib in re.findall( ' \[([^\]]*)\] ' , self.str):
attribs.append(attrib)
self.str = self.str.replace( " [ " + attrib + " ] " , "" )
if len(attribs) > 0:
for attrib in attribs:
try : key, value = attrib.split( ' = ' , 1 )
except : key, value = attrib, ''
self.attributes[key] = value
# Try looking for text
text = None
for text in re.findall( ' \{([^\}]*)\} ' , self.str):
self.str = self.str.replace( " { " + text + " } " , "" )
if text is not None:
self.text = text
# Get the class names
classes = []
for classname in re.findall( ' \.([\$a-zA-Z0-9_\-\&]+) ' , self.str):
classes.append(classname)
if len(classes) > 0:
try : self.attributes[ ' class ' ]
except : self.attributes[ ' class ' ] = ''
self.attributes[ ' class ' ] += ' ' + ' ' .join(classes)
self.attributes[ ' class ' ] = self.attributes[ ' class ' ].strip()
# Get the ID
id = None
for id in re.findall( ' #([\$a-zA-Z0-9_\-\&]+) ' , self.str): pass
if id is not None:
self.attributes[ ' id ' ] = id
# See if there's a multiplier (e.g., "li*3")
multiplier = None
for multiplier in re.findall( ' \*\s*([0-9]+) ' , self.str): pass
if multiplier is not None:
self.multiplier = int(multiplier)
# Populate flag (e.g., ul+)
flags = None
for flags in re.findall( ' [\+\!]+$ ' , self.str): pass
if flags is not None:
if ' + ' in flags: self.populate = True
if ' ! ' in flags: self.expand = True
def __str__ (self):
return self.str
str = ''
parser = None
# For elements
# See the properties of `Element` for description on these.
name = ''
attributes = None
multiplier = 1
expand = False
populate = False
text = ''
opening_tag = None
closing_tag = None
# Type
type = 0
ELEMENT = 2
CHILD = 4
PARENT = 8
SIBLING = 16
# ===============================================================================
class Router:
""" The router.
"""
# Constructor
# ---------------------------------------------------------------------------
def __init__ (self):
pass
# Methods
# ---------------------------------------------------------------------------
def start(self, options = None, str = None, ret = None):
if (options):
self.options = Options(router = self, options = options, argv = None)
else :
self.options = Options(router = self, argv = sys.argv[ 1 :], options = None)
if (self.options.has( ' help ' )):
return self.help()
elif (self.options.has( ' version ' )):
return self.version()
else :
return self.parse(str = str, ret = ret)
def help(self):
print " Usage: %s [OPTIONS] " % sys.argv[0]
print " Expands input into HTML. "
print ""
for short, long, info in self.options.cmdline_keys:
if " Deprecated " in info: continue
if not short == '' : short = ' -%s, ' % short
if not long == '' : long = ' --%s ' % long.replace( " = " , " =XXX " )
print " %6s %-25s %s " % (short, long, info)
print ""
print " \n " .join(self.help_content)
def version(self):
print " Uhm, yeah. "
def parse(self, str = None, ret = None):
self.parser = Parser(self.options)
try :
# Read the files
# for line in fileinput.input(): lines.append(line.rstrip(os.linesep))
if str is not None:
lines = str
else :
lines = sys.stdin.readline()
# lines = [sys.stdin.read()]
# lines = " ".join(lines)
except KeyboardInterrupt:
pass
except :
sys.stderr.write( " Reading failed.\n " )
return
try :
self.parser.load_string(lines)
output = self.parser.render()
if ret: return output
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(output)
win32clipboard.CloseClipboard()
# sys.stdout.write(output)
except :
sys.stderr.write( " Parse error. Check your input.\n " )
print sys.exc_info()[0]
print sys.exc_info()[ 1 ]
def exit(self):
sys.exit()
help_content = [
" Please refer to the manual for more information. " ,
]
# ===============================================================================
class Options:
def __init__ (self, router, argv, options = None):
# Init self
self.router = router
# `options` can be given as a dict of stuff to preload
if options:
for k, v in options.iteritems():
self.options[k] = v
return
# Prepare for getopt()
short_keys, long_keys = "" , []
for short, long, info in self.cmdline_keys: # 'v', 'version'
short_keys += short
long_keys.append(long)
try :
getoptions, arguments = getopt.getopt(argv, short_keys, long_keys)
except getopt.GetoptError:
err = sys.exc_info()[ 1 ]
sys.stderr.write( " Options error: %s\n " % err)
sys.stderr.write( " Try --help for a list of arguments.\n " )
return router.exit()
# Sort them out into options
options = {}
i = 0
for option in getoptions:
key, value = option # '--version', ''
if (value == '' ): value = True
# If the key is long, write it
if key[0: 2 ] == ' -- ' :
clean_key = key[ 2 :]
options[clean_key] = value
# If the key is short, look for the long version of it
elif key[0: 1 ] == ' - ' :
for short, long, info in self.cmdline_keys:
if short == key[ 1 :]:
print long
options[long] = True
# Done
for k, v in options.iteritems():
self.options[k] = v
def __getattr__ (self, attr):
return self.get(attr)
def get(self, attr):
try : return self.options[attr]
except : return None
def has(self, attr):
try : return self.options.has_key(attr)
except : return False
options = {
' indent-spaces ' : 4
}
cmdline_keys = [
( ' h ' , ' help ' , ' Shows help ' ),
( ' v ' , ' version ' , ' Shows the version ' ),
( '' , ' no-guides ' , ' Deprecated ' ),
( '' , ' post-tag-guides ' , ' Adds comments at the end of DIV tags ' ),
( '' , ' textmate ' , ' Adds snippet info (textmate mode) ' ),
( '' , ' indent-spaces= ' , ' Indent spaces ' ),
( '' , ' expand-divs ' , ' Automatically expand divs ' ),
( '' , ' no-last-newline ' , ' Skip the trailing newline ' ),
( '' , ' start-guide-format= ' , ' To be documented ' ),
( '' , ' end-guide-format= ' , ' To be documented ' ),
]
# Property: router
# Router
router = 1
# ===============================================================================
if __name__ == " __main__ " :
if len(sys.argv) > 1 :
s = sys.argv[ 1 ]
else :
s = None
z = Router()
z.start(str = s)
然后配置用户工具,指定刚才保存的python脚本位置:
配置好了以后就可以呼出这个用工具,在弹出框中输入比如: div#header > ul > li*3 > a > span 它帮你生成如下内容的html:
< ul >
< li >
< a href ="" >
< span ></ span >
</ a >
</ li >
< li >
< a href ="" >
< span ></ span >
</ a >
</ li >
< li >
< a href ="" >
< span ></ span >
</ a >
</ li >
</ ul >
</ div >
按两次回车,再按 Ctrl+v 就可以把生成的代码从剪帖板上粘到文档中了,还是挺方便,你也可以将 Argument 调置为 Selection, 这样就可以先在文档中书写 简写码,再选中它执行这个用户工具,具体就看个人喜好了。
3、格式化HTML
一直想着Editplus有象VS那样的酷的代码格式化功能,现在可以使用HTB这个工具来实现,但现在直接指定输入和输出文件为同一个文件好象不正常,不得已只有先输出到一个临时文件里面再用手动拷贝过来,其实也可以写一个Python脚本将生成后的文件内容读取到剪粘板中再粘,就象上一例里面一样,有兴趣的朋友可以自行尝试。
上面的那个 for.htm 就是输出的临时文件, 最后一个参数是 错误输出文件 f:\error.txt ,请自行指定。
4、格式化 PHP 代码
其中的 Argument: --space-after-if --optimize-eol --space-after-switch --space-after-while --space-before-start-angle-bracket --space-after-end-angle-bracket --extra-padding-for-case-statement --glue-amperscore --change-shell-comment-to-double-slashes-comment --indent-with-tab --force-large-php-code-tag --force-true-false-null-contant-lowercase --comment-rendering-style PEAR --equal-align-position 50 --padding-char-count 1 "$(FilePath)"
用到了phpCB.exe (和上面的那个HTB.exe) ,在这里下载。
5、其它的
原来还弄过的两个小工具,格式化js 和 css的看这里
其实都不难,放在这里方便懒人同志,使用中有什么疑问可以发信到 matin0728(AT)gmail.com, QQ5364241,如果你有其它的好东西也可以发给我放在这里跟大家一起分享。谢谢。