def remove_tag(editor): """ Gracefully removes tag under cursor @type editor: ZenEditor """ caret_pos = editor.get_caret_pos() content = editor.get_content() # search for tag pair = html_matcher.get_tags(content, caret_pos, editor.get_profile_name()) if pair and pair[0]: if not pair[1]: # simply remove unary tag editor.replace_content(zen_coding.get_caret_placeholder(), pair[0].start, pair[0].end) else: tag_content_range = narrow_to_non_space(content, pair[0].end, pair[1].start) start_line_bounds = get_line_bounds(content, tag_content_range[0]) start_line_pad = get_line_padding( content[start_line_bounds[0]:start_line_bounds[1]]) tag_content = content[tag_content_range[0]:tag_content_range[1]] tag_content = unindent_text(tag_content, start_line_pad) editor.replace_content( zen_coding.get_caret_placeholder() + tag_content, pair[0].start, pair[1].end) return True else: return False
def remove_tag(editor): """ Gracefully removes tag under cursor @type editor: ZenEditor """ caret_pos = editor.get_caret_pos() content = editor.get_content() # search for tag pair = html_matcher.get_tags(content, caret_pos, editor.get_profile_name()) if pair and pair[0]: if not pair[1]: # simply remove unary tag editor.replace_content(zen_coding.get_caret_placeholder(), pair[0].start, pair[0].end) else: tag_content_range = narrow_to_non_space(content, pair[0].end, pair[1].start) start_line_bounds = get_line_bounds(content, tag_content_range[0]) start_line_pad = get_line_padding(content[start_line_bounds[0]:start_line_bounds[1]]) tag_content = content[tag_content_range[0]:tag_content_range[1]] tag_content = unindent_text(tag_content, start_line_pad) editor.replace_content(zen_coding.get_caret_placeholder() + tag_content, pair[0].start, pair[1].end) return True else: return False
def make_attributes_string(tag, profile): """ Creates HTML attributes string from tag according to profile settings @type tag: ZenNode @type profile: dict """ # make attribute string attrs = '' attr_quote = profile['attr_quotes'] == 'single' and "'" or '"' cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder( ) or '' # use short notation for ID and CLASS attributes for a in tag.attributes: name_lower = a['name'].lower() if name_lower == 'id': attrs += '#' + (a['value'] or cursor) elif name_lower == 'class': attrs += '.' + (a['value'] or cursor) other_attrs = [] # process other attributes for a in tag.attributes: name_lower = a['name'].lower() if name_lower != 'id' and name_lower != 'class': attr_name = profile['attr_case'] == 'upper' and a['name'].upper( ) or name_lower other_attrs.append(':' + attr_name + ' => ' + attr_quote + (a['value'] or cursor) + attr_quote) if other_attrs: attrs += '{' + ', '.join(other_attrs) + '}' return attrs
def process_tag(item, profile, level=0): """ Processes element with <code>tag</code> type @type item: ZenNode @type profile: dict @type level: int """ if not item.name: # looks like it's root element return item attrs = make_attributes_string(item, profile) cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder( ) or '' self_closing = '' is_unary = item.is_unary() and not item.children if profile['self_closing_tag'] and is_unary: self_closing = '/' # define tag name tag_name = '%' + (profile['tag_case'] == 'upper' and item.name.upper() or item.name.lower()) if tag_name.lower() == '%div' and '{' not in attrs: # omit div tag tag_name = '' item.end = '' item.start = _replace(item.start, tag_name + attrs + self_closing) if not item.children and not is_unary: item.start += cursor return item
def insert_formatted_newline(editor, mode='html'): """ Inserts newline character with proper indentation @param editor: Editor instance @type editor: ZenEditor @param mode: Syntax mode (only 'html' is implemented) @type mode: str """ caret_pos = editor.get_caret_pos() nl = zen_coding.get_newline() pad = zen_coding.get_variable('indentation') if mode == 'html': # let's see if we're breaking newly created tag pair = html_matcher.get_tags(editor.get_content(), editor.get_caret_pos(), editor.get_profile_name()) if pair[0] and pair[1] and pair[0]['type'] == 'tag' and pair[0][ 'end'] == caret_pos and pair[1]['start'] == caret_pos: editor.replace_content( nl + pad + zen_coding.get_caret_placeholder() + nl, caret_pos) else: editor.replace_content(nl, caret_pos) else: editor.replace_content(nl, caret_pos) return True
def process_tag(item, profile, level=0): """ Processes element with <code>tag</code> type @type item: ZenNode @type profile: dict @type level: int """ if not item.name: # looks like it's root element return item attrs = make_attributes_string(item, profile) cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder() or '' self_closing = '' is_unary = item.is_unary() and not item.children if profile['self_closing_tag'] and is_unary: self_closing = '/' # define tag name tag_name = '%' + (profile['tag_case'] == 'upper' and item.name.upper() or item.name.lower()) if tag_name.lower() == '%div' and '{' not in attrs: # omit div tag tag_name = '' item.end = '' item.start = _replace(item.start, tag_name + attrs + self_closing) if not item.children and not is_unary: item.start += cursor return item
def make_attributes_string(tag, profile): """ Creates HTML attributes string from tag according to profile settings @type tag: ZenNode @type profile: dict """ # make attribute string attrs = '' attr_quote = profile['attr_quotes'] == 'single' and "'" or '"' cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder() or '' # use short notation for ID and CLASS attributes for a in tag.attributes: name_lower = a['name'].lower() if name_lower == 'id': attrs += '#' + (a['value'] or cursor) elif name_lower == 'class': attrs += '.' + (a['value'] or cursor) other_attrs = [] # process other attributes for a in tag.attributes: name_lower = a['name'].lower() if name_lower != 'id' and name_lower != 'class': attr_name = profile['attr_case'] == 'upper' and a['name'].upper() or name_lower other_attrs.append(':' + attr_name + ' => ' + attr_quote + (a['value'] or cursor) + attr_quote) if other_attrs: attrs += '{' + ', '.join(other_attrs) + '}' return attrs
def generic_comment_toggle(editor, comment_start, comment_end, range_start, range_end): """ Generic comment toggling routine @type editor: ZenEditor @param comment_start: Comment start token @type comment_start: str @param comment_end: Comment end token @type comment_end: str @param range_start: Start selection range @type range_start: int @param range_end: End selection range @type range_end: int @return: bool """ content = editor.get_content() caret_pos = [editor.get_caret_pos()] new_content = None def adjust_caret_pos(m): caret_pos[0] -= len(m.group(0)) return '' def remove_comment(text): """ Remove comment markers from string @param {Sting} str @return {String} """ text = re.sub(r'^' + re.escape(comment_start) + r'\s*', adjust_caret_pos, text) return re.sub(r'\s*' + re.escape(comment_end) + '$', '', text) def has_match(tx, start): return content[start:start + len(tx)] == tx # first, we need to make sure that this substring is not inside comment comment_range = search_comment(content, caret_pos[0], comment_start, comment_end) if comment_range and comment_range[0] <= range_start and comment_range[1] >= range_end: # we're inside comment, remove it range_start, range_end = comment_range new_content = remove_comment(content[range_start:range_end]) else: # should add comment # make sure that there's no comment inside selection new_content = '%s %s %s' % (comment_start, re.sub(re.escape(comment_start) + r'\s*|\s*' + re.escape(comment_end), '', content[range_start:range_end]), comment_end) # adjust caret position caret_pos[0] += len(comment_start) + 1 # replace editor content if new_content is not None: d = caret_pos[0] - range_start new_content = new_content[0:d] + zen_coding.get_caret_placeholder() + new_content[d:] editor.replace_content(unindent(editor, new_content), range_start, range_end) return True return False
def add_placeholders(self, text): _ix = [0] def get_ix(m): _ix[0] += 1 return "$%s" % _ix[0] text = re.sub(r"\$", "\\$", text) return re.sub(zen.get_caret_placeholder(), get_ix, text)
def add_placeholders(self, text): _ix = [zen.max_tabstop] def get_ix(m): _ix[0] += 1 return '$%s' % _ix[0] text = re.sub(r'\$(?![\d\{])', '\\$', text) return re.sub(zen.get_caret_placeholder(), get_ix, text)
def add_placeholders(self, text): _ix = [0] def get_ix(m): _ix[0] += 1 return '$%s' % _ix[0] text = re.sub(r'\$', '\\$', text) return re.sub(zen.get_caret_placeholder(), get_ix, text)
def add_placeholders(self, text): _ix = [zen.max_tabstop] def get_ix(m): _ix[0] += 1 return "$%s" % _ix[0] text = re.sub(r"\$(?![\d\{])", "\\$", text) return re.sub(zen.get_caret_placeholder(), get_ix, text)
def add_placeholders(self, text): _ix = [0] def get_ix(m): if not _ix[0]: _ix[0] += 1 return '$0' else: return '' text = re.sub(r'\$', '\\$', text) return re.sub(zen_coding.get_caret_placeholder(), get_ix, text)
def split_join_tag(editor, profile_name=None): """ Splits or joins tag, e.g. transforms it into a short notation and vice versa: <div></div> → <div /> : join <div /> → <div></div> : split @param editor: Editor instance @type editor: ZenEditor @param profile_name: Profile name @type profile_name: str """ caret_pos = editor.get_caret_pos() profile = zen_coding.get_profile(profile_name or editor.get_profile_name()) caret = zen_coding.get_caret_placeholder() # find tag at current position pair = html_matcher.get_tags(editor.get_content(), caret_pos, profile_name or editor.get_profile_name()) if pair and pair[0]: new_content = pair[0].full_tag if pair[1]: # join tag closing_slash = '' if profile['self_closing_tag'] is True: closing_slash = '/' elif profile['self_closing_tag'] == 'xhtml': closing_slash = ' /' new_content = re.sub(r'\s*>$', closing_slash + '>', new_content) # add caret placeholder if len(new_content) + pair[0].start < caret_pos: new_content += caret else: d = caret_pos - pair[0].start new_content = new_content[0:d] + caret + new_content[d:] editor.replace_content(new_content, pair[0].start, pair[1].end) else: # split tag nl = zen_coding.get_newline() pad = zen_coding.get_variable('indentation') # define tag content depending on profile tag_content = profile[ 'tag_nl'] is True and nl + pad + caret + nl or caret new_content = '%s%s</%s>' % (re.sub( r'\s*\/>$', '>', new_content), tag_content, pair[0].name) editor.replace_content(new_content, pair[0].start, pair[0].end) return True else: return False
def split_join_tag(editor, profile_name=None): """ Splits or joins tag, e.g. transforms it into a short notation and vice versa: <div></div> → <div /> : join <div /> → <div></div> : split @param editor: Editor instance @type editor: ZenEditor @param profile_name: Profile name @type profile_name: str """ caret_pos = editor.get_caret_pos() profile = zen_coding.get_profile(profile_name or editor.get_profile_name()) caret = zen_coding.get_caret_placeholder() # find tag at current position pair = html_matcher.get_tags(editor.get_content(), caret_pos, profile_name or editor.get_profile_name()) if pair and pair[0]: new_content = pair[0].full_tag if pair[1]: # join tag closing_slash = '' if profile['self_closing_tag'] is True: closing_slash = '/' elif profile['self_closing_tag'] == 'xhtml': closing_slash = ' /' new_content = re.sub(r'\s*>$', closing_slash + '>', new_content) # add caret placeholder if len(new_content) + pair[0].start < caret_pos: new_content += caret else: d = caret_pos - pair[0].start new_content = new_content[0:d] + caret + new_content[d:] editor.replace_content(new_content, pair[0].start, pair[1].end) else: # split tag nl = zen_coding.get_newline() pad = zen_coding.get_variable('indentation') # define tag content depending on profile tag_content = profile['tag_nl'] is True and nl + pad + caret + nl or caret new_content = '%s%s</%s>' % (re.sub(r'\s*\/>$', '>', new_content), tag_content, pair[0].name) editor.replace_content(new_content, pair[0].start, pair[0].end) return True else: return False
def make_attributes_string(tag, profile): """ Creates HTML attributes string from tag according to profile settings @type tag: ZenNode @type profile: dict """ # make attribute string attrs = "" attr_quote = profile["attr_quotes"] == "single" and "'" or '"' cursor = profile["place_cursor"] and zen_coding.get_caret_placeholder() or "" # process other attributes for a in tag.attributes: attr_name = profile["attr_case"] == "upper" and a["name"].upper() or a["name"].lower() attrs += " " + attr_name + "=" + attr_quote + (a["value"] or cursor) + attr_quote return attrs
def make_attributes_string(tag, profile): """ Creates HTML attributes string from tag according to profile settings @type tag: ZenNode @type profile: dict """ # make attribute string attrs = '' attr_quote = profile['attr_quotes'] == 'single' and "'" or '"' cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder() or '' # process other attributes for a in tag.attributes: attr_name = profile['attr_case'] == 'upper' and a['name'].upper() or a['name'].lower() attrs += ' ' + attr_name + '=' + attr_quote + (a['value'] or cursor) + attr_quote return attrs
def update_image_size(editor): """ Updates <img> tag's width and height attributes @type editor: ZenEditor @since: 0.65 """ editor_file = editor.get_file_path() caret_pos = editor.get_caret_pos() if editor_file is None: raise ZenError("You should save your file before using this action") image = _find_image(editor) if image: # search for image path m = re.search(r'src=(["\'])(.+?)\1', image['tag'], re.IGNORECASE) if m: src = zen_file.locate_file(editor.get_file_path(), m.group(2)) if not src: raise ZenError("Can't locate file %s" % m.group(2)) stream = zen_file.read(src) if not stream: raise ZenError("Can't read file %s" % src) size = zen_coding.get_image_size(zen_file.read(src)) if size: new_tag = _replace_or_append(image['tag'], 'width', size['width']) new_tag = _replace_or_append(new_tag, 'height', size['height']) # try to preserve caret position if caret_pos < image['start'] + len(new_tag): relative_pos = caret_pos - image['start'] new_tag = new_tag[: relative_pos] + zen_coding.get_caret_placeholder( ) + new_tag[relative_pos:] editor.replace_content(new_tag, image['start'], image['end']) return True return False
def make_attributes_string(tag, profile): """ Creates HTML attributes string from tag according to profile settings @type tag: ZenNode @type profile: dict """ # make attribute string attrs = '' attr_quote = profile['attr_quotes'] == 'single' and "'" or '"' cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder( ) or '' # process other attributes for a in tag.attributes: attr_name = profile['attr_case'] == 'upper' and a['name'].upper( ) or a['name'].lower() attrs += ' ' + attr_name + '=' + attr_quote + (a['value'] or cursor) + attr_quote return attrs
def process_tag(item, profile, level): """ Processes element with <code>tag</code> type @type item: ZenNode @type profile: dict @type level: int """ if not item.name: # looks like it's root element return item attrs = make_attributes_string(item, profile) cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder( ) or '' self_closing = '' is_unary = item.is_unary() and not item.children start = '' end = '' if profile['self_closing_tag'] == 'xhtml': self_closing = ' /' elif profile['self_closing_tag'] is True: self_closing = '/' # define opening and closing tags tag_name = profile['tag_case'] == 'upper' and item.name.upper( ) or item.name.lower() if is_unary: start = '<' + tag_name + attrs + self_closing + '>' item.end = '' else: start = '<' + tag_name + attrs + '>' end = '</' + tag_name + '>' item.start = _replace(item.start, start) item.end = _replace(item.end, end) if not item.children and not is_unary: item.start += cursor return item
def update_image_size(editor): """ Updates <img> tag's width and height attributes @type editor: ZenEditor @since: 0.65 """ editor_file = editor.get_file_path() caret_pos = editor.get_caret_pos() if editor_file is None: raise ZenError("You should save your file before using this action") image = _find_image(editor) if image: # search for image path m = re.search(r'src=(["\'])(.+?)\1', image['tag'], re.IGNORECASE) if m: src = zen_file.locate_file(editor.get_file_path(), m.group(2)) if not src: raise ZenError("Can't locate file %s" % m.group(2)) stream = zen_file.read(src) if not stream: raise ZenError("Can't read file %s" % src) size = zen_coding.get_image_size(zen_file.read(src)) if size: new_tag = _replace_or_append(image['tag'], 'width', size['width']) new_tag = _replace_or_append(new_tag, 'height', size['height']) # try to preserve caret position if caret_pos < image['start'] + len(new_tag): relative_pos = caret_pos - image['start'] new_tag = new_tag[:relative_pos] + zen_coding.get_caret_placeholder() + new_tag[relative_pos:] editor.replace_content(new_tag, image['start'], image['end']) return True return False
def process_tag(item, profile, level): """ Processes element with <code>tag</code> type @type item: ZenNode @type profile: dict @type level: int """ if not item.name: # looks like it's root element return item attrs = make_attributes_string(item, profile) cursor = profile['place_cursor'] and zen_coding.get_caret_placeholder() or '' self_closing = '' is_unary = item.is_unary() and not item.children start= '' end = '' if profile['self_closing_tag'] == 'xhtml': self_closing = ' /' elif profile['self_closing_tag'] is True: self_closing = '/' # define opening and closing tags tag_name = profile['tag_case'] == 'upper' and item.name.upper() or item.name.lower() if is_unary: start = '<' + tag_name + attrs + self_closing + '>' item.end = '' else: start = '<' + tag_name + attrs + '>' end = '</' + tag_name + '>' item.start = _replace(item.start, start) item.end = _replace(item.end, end) if not item.children and not is_unary: item.start += cursor return item
def process_tag(item, profile, level): """ Processes element with <code>tag</code> type @type item: ZenNode @type profile: dict @type level: int """ if not item.name: # looks like it's root element return item attrs = make_attributes_string(item, profile) cursor = profile["place_cursor"] and zen_coding.get_caret_placeholder() or "" self_closing = "" is_unary = item.is_unary() and not item.children start = "" end = "" if profile["self_closing_tag"] == "xhtml": self_closing = " /" elif profile["self_closing_tag"] is True: self_closing = "/" # define opening and closing tags tag_name = profile["tag_case"] == "upper" and item.name.upper() or item.name.lower() if is_unary: start = "<" + tag_name + attrs + self_closing + ">" item.end = "" else: start = "<" + tag_name + attrs + ">" end = "</" + tag_name + ">" item.start = _replace(item.start, start) item.end = _replace(item.end, end) if not item.children and not is_unary: item.start += cursor return item
def insert_formatted_newline(editor, mode='html'): """ Inserts newline character with proper indentation @param editor: Editor instance @type editor: ZenEditor @param mode: Syntax mode (only 'html' is implemented) @type mode: str """ caret_pos = editor.get_caret_pos() nl = zen_coding.get_newline() pad = zen_coding.get_variable('indentation') if mode == 'html': # let's see if we're breaking newly created tag pair = html_matcher.get_tags(editor.get_content(), editor.get_caret_pos(), editor.get_profile_name()) if pair[0] and pair[1] and pair[0]['type'] == 'tag' and pair[0]['end'] == caret_pos and pair[1]['start'] == caret_pos: editor.replace_content(nl + pad + zen_coding.get_caret_placeholder() + nl, caret_pos) else: editor.replace_content(nl, caret_pos) else: editor.replace_content(nl, caret_pos) return True