def do_css_reflection(editor): content = editor.get_content() caret_pos = editor.get_caret_pos() css = parser_utils.extract_css_rule(content, caret_pos) if not css or caret_pos < css[0] or caret_pos > css[1]: # no matching CSS rule or caret outside rule bounds return False tokens = parser_utils.parse_css(content[css[0]:css[1]], css[0]) token_ix = find_token_from_position(tokens, caret_pos, 'identifier') if token_ix != -1: cur_prop = tokens[token_ix]['content'] value_token = find_value_token(tokens, token_ix + 1) base_name = get_base_css_name(cur_prop) re_name = re.compile('^(?:\\-\\w+\\-)?' + base_name + '$') re_name = get_reflected_css_name(base_name) values = [] if not value_token: return False # search for all vendor-prefixed properties for i, token in enumerate(tokens): if token['type'] == 'identifier' and re.search( re_name, token['content']) and token['content'] != cur_prop: v = find_value_token(tokens, i + 1) if v: values.append({'name': token, 'value': v}) # some editors do not provide easy way to replace multiple code # fragments so we have to squash all replace operations into one if values: data = content[ values[0]['value']['start']:values[-1]['value']['end']] offset = values[0]['value']['start'] value = value_token['content'] values.reverse() for v in values: rv = get_reflected_value(cur_prop, value, v['name']['content'], v['value']['content']) data = replace_substring(data, v['value']['start'] - offset, v['value']['end'] - offset, rv) # also calculate new caret position if v['value']['start'] < caret_pos: caret_pos += len(rv) - len(v['value']['content']) return { 'data': data, 'start': offset, 'end': values[0]['value']['end'], 'caret': caret_pos } return None
def do_css_reflection(editor): content = editor.get_content() caret_pos = editor.get_caret_pos() css = parser_utils.extract_css_rule(content, caret_pos) if not css or caret_pos < css[0] or caret_pos > css[1]: # no matching CSS rule or caret outside rule bounds return False tokens = parser_utils.parse_css(content[css[0]:css[1]], css[0]) token_ix = find_token_from_position(tokens, caret_pos, 'identifier') if token_ix != -1: cur_prop = tokens[token_ix]['content'] value_token = find_value_token(tokens, token_ix + 1) base_name = get_base_css_name(cur_prop) re_name = re.compile('^(?:\\-\\w+\\-)?' + base_name + '$') re_name = get_reflected_css_name(base_name) values = [] if not value_token: return False # search for all vendor-prefixed properties for i, token in enumerate(tokens): if token['type'] == 'identifier' and re.search(re_name, token['content']) and token['content'] != cur_prop: v = find_value_token(tokens, i + 1) if v: values.append({'name': token, 'value': v}) # some editors do not provide easy way to replace multiple code # fragments so we have to squash all replace operations into one if values: data = content[values[0]['value']['start']:values[-1]['value']['end']] offset = values[0]['value']['start'] value = value_token['content'] values.reverse() for v in values: rv = get_reflected_value(cur_prop, value, v['name']['content'], v['value']['content']) data = replace_substring(data, v['value']['start'] - offset, v['value']['end'] - offset, rv) # also calculate new caret position if v['value']['start'] < caret_pos: caret_pos += len(rv) - len(v['value']['content']) return { 'data': data, 'start': offset, 'end': values[0]['value']['end'], 'caret': caret_pos } return None
def do_css_reflection(editor): content = editor.get_content() caret_pos = editor.get_caret_pos() css = parser_utils.extract_css_rule(content, caret_pos) if not css or caret_pos < css[0] or caret_pos > css[1]: # no matching CSS rule or caret outside rule bounds return False tokens = parser_utils.parse_css(content[css[0] : css[1]], css[0]) token_ix = find_token_from_position(tokens, caret_pos, "identifier") if token_ix != -1: cur_prop = tokens[token_ix]["content"] value_token = find_value_token(tokens, token_ix + 1) base_name = get_base_css_name(cur_prop) re_name = re.compile("^(?:\\-\\w+\\-)?" + base_name + "$") re_name = get_reflected_css_name(base_name) values = [] if not value_token: return False # search for all vendor-prefixed properties for i, token in enumerate(tokens): if token["type"] == "identifier" and re.search(re_name, token["content"]) and token["content"] != cur_prop: v = find_value_token(tokens, i + 1) if v: values.append({"name": token, "value": v}) # some editors do not provide easy way to replace multiple code # fragments so we have to squash all replace operations into one if values: data = content[values[0]["value"]["start"] : values[-1]["value"]["end"]] offset = values[0]["value"]["start"] value = value_token["content"] values.reverse() for v in values: rv = get_reflected_value(cur_prop, value, v["name"]["content"], v["value"]["content"]) data = replace_substring(data, v["value"]["start"] - offset, v["value"]["end"] - offset, rv) # also calculate new caret position if v["value"]["start"] < caret_pos: caret_pos += len(rv) - len(v["value"]["content"]) return {"data": data, "start": offset, "end": values[0]["value"]["end"], "caret": caret_pos} return None
def update_image_size_css(editor): """ Updates image size of CSS rule @type editor: ZenEditor """ caret_pos = editor.get_caret_pos() content = editor.get_content() rule = parser_utils.extract_css_rule(content, caret_pos, True) if rule: css = parser_utils.parse_css(content[rule[0]:rule[1]], rule[0]) cur_token = find_token_from_position(css, caret_pos, 'identifier') value = find_value_token(css, cur_token + 1) if not value: return False # find insertion point ins_point = find_css_insertion_point(css, cur_token) m = re.match(r'url\((["\']?)(.+?)\1\)', value['content'], re.I) if m: size = get_image_size_for_source(editor, m.group(2)) if size: wh = {'width': None, 'height': None} updates = [] styler = learn_css_style(css, cur_token) for i, item in enumerate(css): if item['type'] == 'identifier' and item['content'] in wh: wh[item['content']] = i def update(name, val): v = None if wh[name] is not None: v = find_value_token(css, wh[name] + 1) if v: updates.append([v['start'], v['end'], '%spx' % val]) else: updates.append([ ins_point['token']['end'], ins_point['token']['end'], styler(name, '%spx' % val) ]) update('width', size['width']) update('height', size['height']) if updates: updates.sort(lambda a, b: a[0] - b[0]) # updates = sorted(updates, key=lambda a: a[0]) # some editors do not provide easy way to replace multiple code # fragments so we have to squash all replace operations into one offset = updates[0][0] offset_end = updates[-1][1] data = content[offset:offset_end] updates.reverse() for u in updates: data = replace_substring(data, u[0] - offset, u[1] - offset, u[2]) # also calculate new caret position if u[0] < caret_pos: caret_pos += len(u[2]) - u[1] + u[0] if ins_point['need_col']: data = replace_substring( data, ins_point['token']['end'] - offset, ins_point['token']['end'] - offset, ';') return { 'data': data, 'start': offset, 'end': offset_end, 'caret': caret_pos } return None
def update_image_size_css(editor): """ Updates image size of CSS rule @type editor: ZenEditor """ caret_pos = editor.get_caret_pos() content = editor.get_content() rule = parser_utils.extract_css_rule(content, caret_pos, True) if rule: css = parser_utils.parse_css(content[rule[0]:rule[1]], rule[0]) cur_token = find_token_from_position(css, caret_pos, 'identifier') value = find_value_token(css, cur_token + 1) if not value: return False # find insertion point ins_point = find_css_insertion_point(css, cur_token) m = re.match(r'url\((["\']?)(.+?)\1\)', value['content'], re.I) if m: size = get_image_size_for_source(editor, m.group(2)) if size: wh = {'width': None, 'height': None} updates = [] styler = learn_css_style(css, cur_token) for i, item in enumerate(css): if item['type'] == 'identifier' and item['content'] in wh: wh[item['content']] = i def update(name, val): v = None if wh[name] is not None: v = find_value_token(css, wh[name] + 1) if v: updates.append([v['start'], v['end'], '%spx' % val]) else: updates.append([ins_point['token']['end'], ins_point['token']['end'], styler(name, '%spx' % val)]) update('width', size['width']) update('height', size['height']) if updates: updates.sort(lambda a,b: a[0] - b[0]) # updates = sorted(updates, key=lambda a: a[0]) # some editors do not provide easy way to replace multiple code # fragments so we have to squash all replace operations into one offset = updates[0][0] offset_end = updates[-1][1] data = content[offset:offset_end] updates.reverse() for u in updates: data = replace_substring(data, u[0] - offset, u[1] - offset, u[2]) # also calculate new caret position if u[0] < caret_pos: caret_pos += len(u[2]) - u[1] + u[0] if ins_point['need_col']: data = replace_substring(data, ins_point['token']['end'] - offset, ins_point['token']['end'] - offset, ';') return { 'data': data, 'start': offset, 'end': offset_end, 'caret': caret_pos }; return None
def get_range_for_prev_item_in_css(rule, offset, sel_start, sel_end): """ Returns range for item to be selected in CSS rule before current caret position @param rule: CSS rule declaration @type rule: str @param offset: Rule's position index inside content @type offset: int @param sel_start: Start index of user selection @type sel_start: int @param sel_end: End index of user selection @type sel_end: int @return: List with two indexes if next item was found, None otherwise """ tokens = parser_utils.parse_css(rule, offset) next = [] def check_same_range(r): "Same range is used inside complex value processor" return r[0] == sel_start and r[1] == sel_end # search for token that is left to the selection for i in range(len(tokens) - 1, -1, -1): token = tokens[i] if token['type'] in known_css_types: # check token position pos_test = token['start'] < sel_start if token['type'] == 'value' and token['ref_start_ix'] != token[ 'ref_end_ix']: # respect complex values pos_test = token['start'] <= sel_start if not pos_test: continue # found token that should be selected if token['type'] == 'identifier': rule_sel = handle_full_rule_css(tokens, i, token['start']) if rule_sel: return rule_sel elif token['type'] == 'value' and token['ref_start_ix'] != token[ 'ref_end_ix']: # looks like a complex value children = token['children'] for child in children: if child[0] < sel_start: # create array copy next = [child[0], child[1]] rule_sel = handle_css_special_case( rule, next[0], next[1], offset) return not check_same_range( rule_sel) and rule_sel or next # if we are here than we already traversed trough all # child tokens, select full value next = [token['start'], token['end']] if not check_same_range(next): return next else: return [token['start'], token['end']] return None
def get_range_for_next_item_in_css(rule, offset, sel_start, sel_end): """ Returns range for item to be selected in tag after current caret position @param rule: CSS rule declaration @type rule: str @param offset: Rule's position index inside content @type offset: int @param sel_start: Start index of user selection @type sel_start: int @param sel_end: End index of user selection @type sel_end: int @return: List with two indexes if next item was found, None otherwise """ tokens = parser_utils.parse_css(rule, offset) next = [] def check_same_range(r): "Same range is used inside complex value processor" return r[0] == sel_start and r[1] == sel_end # search for token that is right to selection for i, token in enumerate(tokens): if token['type'] in known_css_types: # check token position if sel_start == sel_end: pos_test = token['end'] > sel_start else: pos_test = token['start'] >= sel_start if token['type'] == 'value': # respect complex values pos_test = pos_test or sel_start >= token[ 'start'] and token['end'] >= sel_end if not pos_test: continue # found token that should be selected if token['type'] == 'identifier': rule_sel = handle_full_rule_css( tokens, i, sel_end <= token['end'] and token['start'] or -1) if rule_sel: return rule_sel elif token['type'] == 'value' and sel_end > token[ 'start'] and token['children']: # looks like a complex value children = token['children'] for child in children: if child[0] >= sel_start or (sel_start == sel_end and child[1] > sel_start): next = [child[0], child[1]] if check_same_range(next): rule_sel = handle_css_special_case( rule, next[0], next[1], offset) if not check_same_range(rule_sel): return rule_sel else: continue return next elif token['end'] > sel_end: return [token['start'], token['end']] return None
def get_range_for_prev_item_in_css(rule, offset, sel_start, sel_end): """ Returns range for item to be selected in CSS rule before current caret position @param rule: CSS rule declaration @type rule: str @param offset: Rule's position index inside content @type offset: int @param sel_start: Start index of user selection @type sel_start: int @param sel_end: End index of user selection @type sel_end: int @return: List with two indexes if next item was found, None otherwise """ tokens = parser_utils.parse_css(rule, offset) next = [] def check_same_range(r): "Same range is used inside complex value processor" return r[0] == sel_start and r[1] == sel_end # search for token that is left to the selection for i in range(len(tokens) - 1, -1, -1): token = tokens[i] if token['type'] in known_css_types: # check token position pos_test = token['start'] < sel_start if token['type'] == 'value' and token['ref_start_ix'] != token['ref_end_ix']: # respect complex values pos_test = token['start'] <= sel_start if not pos_test: continue # found token that should be selected if token['type'] == 'identifier': rule_sel = handle_full_rule_css(tokens, i, token['start']) if rule_sel: return rule_sel elif token['type'] == 'value' and token['ref_start_ix'] != token['ref_end_ix']: # looks like a complex value children = token['children'] for child in children: if child[0] < sel_start: # create array copy next = [child[0], child[1]] rule_sel = handle_css_special_case(rule, next[0], next[1], offset) return not check_same_range(rule_sel) and rule_sel or next # if we are here than we already traversed trough all # child tokens, select full value next = [token['start'], token['end']] if not check_same_range(next): return next else: return [token['start'], token['end']] return None
def get_range_for_next_item_in_css(rule, offset, sel_start, sel_end): """ Returns range for item to be selected in tag after current caret position @param rule: CSS rule declaration @type rule: str @param offset: Rule's position index inside content @type offset: int @param sel_start: Start index of user selection @type sel_start: int @param sel_end: End index of user selection @type sel_end: int @return: List with two indexes if next item was found, None otherwise """ tokens = parser_utils.parse_css(rule, offset) next = [] def check_same_range(r): "Same range is used inside complex value processor" return r[0] == sel_start and r[1] == sel_end # search for token that is right to selection for i, token in enumerate(tokens): if token['type'] in known_css_types: # check token position if sel_start == sel_end: pos_test = token['end'] > sel_start else: pos_test = token['start'] >= sel_start if token['type'] == 'value': # respect complex values pos_test = pos_test or sel_start >= token['start'] and token['end'] >= sel_end if not pos_test: continue # found token that should be selected if token['type'] == 'identifier': rule_sel = handle_full_rule_css(tokens, i, sel_end <= token['end'] and token['start'] or -1) if rule_sel: return rule_sel elif token['type'] == 'value' and sel_end > token['start'] and token['children']: # looks like a complex value children = token['children'] for child in children: if child[0] >= sel_start or (sel_start == sel_end and child[1] > sel_start): next = [child[0], child[1]] if check_same_range(next): rule_sel = handle_css_special_case(rule, next[0], next[1], offset) if not check_same_range(rule_sel): return rule_sel else: continue return next elif token['end'] > sel_end: return [token['start'], token['end']] return None