def match_pair(editor, direction='out'): """ Find and select HTML tag pair @param editor: Editor instance @type editor: ZenEditor @param direction: Direction of pair matching: 'in' or 'out'. @type direction: str """ direction = direction.lower() range_start, range_end = editor.get_selection_range() cursor = range_end content = editor.get_content() range = None old_open_tag = html_matcher.last_match['opening_tag'] old_close_tag = html_matcher.last_match['closing_tag'] if direction == 'in' and old_open_tag and range_start != range_end: # user has previously selected tag and wants to move inward if not old_close_tag: # unary tag was selected, can't move inward return False elif old_open_tag['start'] == range_start: raise Exception, 'search inward' if content[old_open_tag['end']] == '<': # test if the first inward tag matches the entire parent tag's content _r = html_matcher.find(content, old_open_tag['end'] + 1) if _r[0] == old_open_tag['end'] and _r[1] == old_close_tag['start']: range = html_matcher.match(content, old_open_tag['end'] + 1) else: range = (old_open_tag['end'], old_close_tag['start']) else: range = (old_open_tag['end'], old_close_tag['start']) else: new_cursor = content[0, old_close_tag['start']].find('<', old_open_tag['end']) search_pos = new_cursor + 1 if new_cursor != -1 else old_open_tag['end'] range = html_matcher.match(content, search_pos) else: range = html_matcher.match(content, cursor) if range[0] is not None: editor.create_selection(range[0], range[1]) return True else: return False
def go_to_matching_pair(editor): """ Moves caret to matching opening or closing tag @param editor: Editor instance @type editor: ZenEditor """ content = editor.get_content() caret_pos = editor.get_caret_pos() if content[caret_pos] == '<': # looks like caret is outside of tag pair caret_pos += 1 range = html_matcher.match(content, caret_pos) if range[0] is not None: # match found open_tag = html_matcher.last_match['opening_tag'] close_tag = html_matcher.last_match['closing_tag'] if close_tag: # exclude unary tags if open_tag['start'] <= caret_pos and open_tag['end'] >= caret_pos: editor.set_caret_pos(close_tag['start']) elif close_tag['start'] <= caret_pos and close_tag['end'] >= caret_pos: editor.set_caret_pos(open_tag['start'])
def core_wrap_with_abbreviation(self, abbr): if not abbr: return None syntax = self.get_syntax() profile_name = self.get_profile_name() start_offset, end_offset = self.get_selection_range() content = self.get_content() if start_offset == end_offset: rng = html_matcher.match(content, start_offset, profile_name) if rng[0] is None: return None else: start_offset, end_offset = rng start_offset, end_offset = zen_actions.narrow_to_non_space( content, start_offset, end_offset) line_bounds = zen_actions.get_line_bounds(content, start_offset) padding = zen_actions.get_line_padding( content[line_bounds[0]:line_bounds[1]]) new_content = content[start_offset:end_offset] return zen_core.wrap_with_abbreviation( abbr, zen_actions.unindent_text(new_content, padding), syntax, profile_name)
def wrap_with_abbreviation(editor, abbr, syntax, profile_name='xhtml'): """ Wraps content with abbreviation @param editor: Editor instance @type editor: ZenEditor @param syntax: Syntax type (html, css, etc.) @type syntax: str @param profile_name: Output profile name (html, xml, xhtml) @type profile_name: str """ start_offset, end_offset = editor.get_selection_range() content = editor.get_content() if not abbr: return None if start_offset == end_offset: # no selection, find tag pair range = html_matcher.match(content, start_offset) if range[0] is None: # nothing to wrap return None start_offset = range[0] end_offset = range[1] # narrow down selection until first non-space character while start_offset < end_offset: if not content[start_offset].isspace(): break start_offset += 1 while end_offset > start_offset: end_offset -= 1 if not content[end_offset].isspace(): end_offset += 1 break new_content = content[start_offset:end_offset] result = zen.wrap_with_abbreviation(abbr, unindent(editor, new_content), syntax, profile_name) if result: editor.replace_content(result, start_offset, end_offset)
def merge_lines(editor): """ Merge lines spanned by user selection. If there's no selection, tries to find matching tags and use them as selection @param editor: Editor instance @type editor: ZenEditor """ start, end = editor.get_selection_range() if start == end: # find matching tag pair = html_matcher.match(editor.get_content(), editor.get_caret_pos()) if pair and pair[0] is not None: start, end = pair if start != end: # got range, merge lines text = editor.get_content()[start, end] lines = map(lambda s: re.sub(r'^\s+', '', s), zen.split_by_lines(text)) text = re.sub(r'\s{2,}', ' ', ''.join(lines)) editor.replace_content(text, start, end) editor.create_selection(start, start + len(text))
def core_wrap_with_abbreviation(self, abbr): if not abbr: return None syntax = self.get_syntax() profile_name = self.get_profile_name() start_offset, end_offset = self.get_selection_range() content = self.get_content() if start_offset == end_offset: rng = html_matcher.match(content, start_offset, profile_name) if rng[0] is None: return None else: start_offset, end_offset = rng start_offset, end_offset = zen_actions.narrow_to_non_space(content, start_offset, end_offset) line_bounds = zen_actions.get_line_bounds(content, start_offset) padding = zen_actions.get_line_padding(content[line_bounds[0]:line_bounds[1]]) new_content = content[start_offset:end_offset] return zen_core.wrap_with_abbreviation(abbr, zen_actions.unindent_text(new_content, padding), syntax, profile_name)