1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
"""This file provides enhanced support for editing XML files
It provides a number of new menus, displayed only when an XML file is
being edited:
- /XML/Check Well formedness
The document is parsed, and any error is shown in the Locations window
so that the document can be fixed. This doesn't check the validity with
a DTD or an XML schema, just basic syntax check.
- /XML/Escape Selection
Replace all XML special characters in the current selection (or current
line) by their matching XML entity (e.g. "&")
- /XML/Move to ...
Various submenus to move around the XML file. You can bind key shortcuts
to these through the /Edit/Key Shortcuts editor.
- /XML/View as tree
Open a read-only widget that shows the organization of the XML file
"""
############################################################################
# No user customization below this line
############################################################################
from GPS import EditorBuffer, Console, Locations, XMLViewer, parse_xml
from gps_utils import interactive, in_xml_file
import xml.sax
import xml.sax.handler
import xml.sax.saxutils
import traceback
class StopProcessing (Exception):
pass
class GPSErrorHandler (xml.sax.handler.ErrorHandler):
def __init__(self):
self.output = ''
def add_error(self, prefix, exception):
self.output += '%s:%s:%s: %s %s\n' % (
exception.getSystemId(),
exception.getLineNumber(),
exception.getColumnNumber(),
prefix,
exception.getMessage())
def error(self, exception):
self.add_error('error:', exception)
def fatalError(self, exception):
self.add_error('fatal error:', exception)
raise StopProcessing
def warning(self, exception):
self.add_error('warning:', exception)
@interactive('XML', filter=in_xml_file, name='xml check well formedness')
def check_wf():
"""Check whether the current XML document is well-formed"""
try:
file = EditorBuffer.get().file()
handler = xml.sax.handler.ContentHandler()
errors = GPSErrorHandler()
xml.sax.parse(file.path, handler, errors)
Locations.remove_category('XML well-formedness')
if not errors.output:
Console().write('Document is well-formed\n')
else:
Console().write(errors.output)
Locations.parse(errors.output, 'XML well-formedness')
except StopProcessing:
Locations.parse(errors.output, 'XML well-formedness')
except xml.sax.SAXParseException:
Console().write('Unexpected error while parsing the XML document')
except:
Console().write('Unexpected error %s' % (traceback.format_exc(), ))
@interactive('XML', filter=in_xml_file, name='xml escape selection')
def quote_selection():
"""
Replace XML special characters in the current selection (or current
selection) by their equivalent XML entities.
"""
buffer = EditorBuffer.get()
(min, max) = (buffer.selection_start(), buffer.selection_end())
if min == max:
(min, max) = (buffer.current_view().cursor().beginning_of_line(),
buffer.current_view().cursor().end_of_line())
with buffer.new_undo_group():
text = buffer.get_chars(min, max)
text = xml.sax.saxutils.escape(text)
buffer.delete(min, max)
buffer.insert(min, text)
@interactive('XML', filter=in_xml_file, name='xml view as tree')
def view_as_tree():
try:
buffer = EditorBuffer.get()
view = XMLViewer(buffer.file().path)
view.parse_string(buffer.get_chars())
except:
pass
@interactive("XML", filter=in_xml_file, name="XML move to next open tag")
def next_open_tag():
"""Move to the next opening tag"""
buffer = EditorBuffer.get()
loc = buffer.current_view().cursor() + 1
try:
while loc.get_char() != "<" \
or (loc + 1).get_char() == "/" \
or (loc + 1).get_char() == "!":
loc += 1
buffer.current_view().goto(loc)
except:
# End of file
pass
@interactive("XML", filter=in_xml_file, name="XML move to next close tag")
def next_close_tag():
"""Move to the next closing tag"""
buffer = EditorBuffer.get()
loc = buffer.current_view().cursor() + 1
try:
while loc.get_char() != "<" \
or (loc + 1).get_char() != "/":
loc += 1
buffer.current_view().goto(loc)
except:
# End of file
pass
@interactive("XML", filter=in_xml_file, name="XML move to matching close tag")
def goto_matching_tag():
"""Go to the matching closing tag"""
buffer = EditorBuffer.get()
loc = buffer.current_view().cursor()
try:
while loc.get_char() != '<':
loc -= 1
start = loc + 1
end = start.forward_word()
loc = start.search('</' + buffer.get_chars(start, end - 1),
dialog_on_failure=False,
case_sensitive=True)
if loc:
buffer.current_view().goto(loc[0])
except:
pass
parse_xml('''
<Language>
<Name>XML</Name>
<Body_Suffix>.xml</Body_Suffix>
<Keywords>(</?\w+>?)|(/?>)</Keywords>
<Wordchars><>/</Wordchars>
<Context>
<Comment_Start><!--</Comment_Start>
<Comment_End>--></Comment_End>
<String_Delimiter>"</String_Delimiter>
<Can_Indent>True</Can_Indent>
<Syntax_Highlighting>True</Syntax_Highlighting>
<Case_Sensitive>True</Case_Sensitive>
</Context>
</Language>
<Language>
<Name>HTML</Name>
<Spec_Suffix>.html</Spec_Suffix>
<Parent>XML</Parent>
</Language>''')
|