import re import color, method, mode from lex import Grammar, Rule, PatternRule, RegionRule, PatternMatchRule class StringGrammar1(Grammar): rules = [ PatternRule('data', '[^"&]+'), PatternRule('escaped', '&[a-z]+;'), ] class StringGrammar2(Grammar): rules = [ PatternRule('data', r"[^'&]+"), PatternRule('escaped', '&[a-z]+;'), ] class CDataGrammar(Grammar): rules = [PatternRule('data', r'(?:[^\]]|\](?!\])|\]\](?!>))+')] class CommentGrammar(Grammar): rules = [PatternRule('data', '(?:[^-]|-(?!-)|--(?!>))+')] class TagGrammar(Grammar): rules = [ PatternRule('attrname', '[a-zA-Z_][-a-zA-Z0-9_]*(?==)'), PatternRule('namespace', '[a-zA-Z_]+(?=:)'), PatternRule('name', '[a-zA-Z_][-a-zA-Z0-9_]*'), PatternRule('delimiter', '[:/=]'), RegionRule('string', '"', StringGrammar1, '"'), RegionRule('string', "'", StringGrammar2, "'"), PatternRule('spaces', ' +'), PatternRule('eol', r'\n'), ] class MetadataGrammar(Grammar): rules = [PatternRule('meta', r'\?(?:xml)?')] + TagGrammar.rules class DoctypeGrammar(Grammar): rules = [PatternRule('doctype', '!DOCTYPE')] + TagGrammar.rules class XMLGrammar(Grammar): rules = [ # TODO: how does cdata work again? PatternRule('data', r'[^<& \n]+'), PatternRule('spaces', ' +'), PatternRule('xml.entity', '&[a-z]+;'), PatternRule('eol', r'\n'), PatternMatchRule('x', '(<)(/)([a-zA-Z_][a-zA-Z0-9_]*)(>)', 'xml.tag.start', 'xml.tag.delimiter', 'xml.tag.name', 'xml.tag.end'), RegionRule('xml.tag', r'<(?![\?!])', TagGrammar, '/?>'), RegionRule('xml.tag', r'<(?![\?!])', TagGrammar, '/?>'), RegionRule('comment', ''), RegionRule('xml.tag', r'<(?=\?)', MetadataGrammar, r'\?>'), RegionRule('xml.tag', '<(?!!)', DoctypeGrammar, '>'), RegionRule('xml.cdata', r''), ] class XmlValidate(method.shell.Exec): '''Valid the buffer's contents as valid XML.''' show_success = True args = [] def _execute(self, w, **vargs): self._doit(w, w.buffer.path, 'xmlwf %(path)r', cmdname='xml-validate') class XmlCreateTag(method.Method): '''Create an opening and closing tag''' args = [method.Argument('tagname', prompt="Tag Name: ", help="Create an open/close tag pair")] def _execute(self, w, **vargs): t = vargs['tagname'] w.insert_string_at_cursor("<%s>" % t) p = w.logical_cursor() w.insert_string_at_cursor("" % t) w.goto(p) class XmlCreateComment(method.Method): '''Create an opening and closing tag''' def _execute(self, w, **vargs): w.insert_string_at_cursor("") w.goto(p) class XmlCreateCdata(method.Method): '''Create an opening and closing tag''' def _execute(self, w, **vargs): w.insert_string_at_cursor("") w.goto(p) class XML(mode.Fundamental): name = 'XML' extensions = ['.xml', '.xml.in', '.xsl', '.xsd'] detection = [re.compile(r'^<\?xml')] grammar = XMLGrammar colors = { 'xml.tag.meta': ('magenta', 'default', 'bold'), 'xml.tag.doctype': ('magenta', 'default', 'bold'), 'xml.tag.start': ('default', 'default', 'bold'), 'xml.tag.namespace': ('magenta', 'default', 'bold'), 'xml.tag.name': ('blue', 'default', 'bold'), 'xml.tag.attrname': ('cyan', 'default', 'bold'), 'xml.tag.end': ('default', 'default', 'bold'), 'xml.entity': ('magenta', 'default', 'bold'), 'xml.cdata.start': ('magenta', 'default', 'bold'), 'xml.cdata.data': ('green', 'default', 'bold'), 'xml.cdata.end': ('magenta', 'default', 'bold'), } actions = [XmlValidate, XmlCreateTag, XmlCreateComment, XmlCreateCdata] _bindings = { 'xml-create-tag': ('M-t',), } install = XML.install