def length_expand(css_dict, name, value, unit, options=None): if options is None: options = {} if unit and 'percents'.startswith(unit): unit = '%' if isinstance(value, float): full_unit = options.get('CSS_default_unit_decimal', 'em') else: full_unit = options.get('CSS_default_unit', 'px') if '<number>' in [ val for prop, val in get_flat_css(css_dict) if prop == name ] and not options.get('CSS_units_for_unitless_numbers'): full_unit = '' if value == 0: return '0' if value == '': return '' if unit: units = (val[1:] for key, val in get_flat_css(css_dict) if key == name and val.startswith('.')) req_units = [u for u in units if sub_string(u, unit)] PRIORITY = ("em", "ex", "vw", "vh", "vmin", "vmax" "vm", "ch", "rem", "px", "cm", "mm", "in", "pt", "pc") full_unit = hayaku_extract(unit, req_units, PRIORITY) if not full_unit: full_unit = unit return '{0}{1}'.format(value, full_unit)
def length_expand(css_dict, name, value, unit, options=None): if options is None: options = {} if unit and 'percents'.startswith(unit): unit = '%' if isinstance(value, float): full_unit = options.get('CSS_default_unit_decimal', 'em') else: full_unit = options.get('CSS_default_unit', 'px') if '<number>' in [val for prop, val in get_flat_css(css_dict) if prop == name] and not options.get('CSS_units_for_unitless_numbers'): full_unit = '' if value == 0: return '0' if value == '': return '' if unit: units = (val[1:] for key, val in get_flat_css(css_dict) if key == name and val.startswith('.')) req_units = [u for u in units if sub_string(u, unit)] PRIORITY = ("em", "ex", "vw", "vh", "vmin", "vmax" "vm", "ch", "rem", "px", "cm", "mm", "in", "pt", "pc") full_unit = hayaku_extract(unit, req_units, PRIORITY) if not full_unit: full_unit = unit return '{0}{1}'.format(value, full_unit)
def expand_value(args, css_dict=None, options=None): if css_dict is None: css_dict = get_css_dict()[0] if 'keyword-value' in args: return args['keyword-value'] if args['property-name'] in set(p for p, v in get_flat_css(css_dict) if v == '<color_values>'): if 'color' in args and not args['color']: return '#' return color_expand(args.get('color', ''),args.get('color_alpha', 1)) elif args['property-name'] in set(p for p, v in get_flat_css(css_dict) if v.startswith('.')) and 'keyword-value' not in args: ret = length_expand(css_dict, args['property-name'], args.get('type-value', ''), args.get('type-name', ''), options) return ret elif 'type-value' in args: return str(args['type-value']) return args.get('keyword-value', '')
def expand_value(args, css_dict=None, options=None): if css_dict is None: css_dict = get_css_dict()[0] if 'keyword-value' in args: return args['keyword-value'] if args['property-name'] in set(p for p, v in get_flat_css(css_dict) if v == '<color_values>'): if 'color' in args and not args['color']: return '#' return color_expand(args.get('color', ''), args.get('color_alpha', 1)) elif args['property-name'] in set( p for p, v in get_flat_css(css_dict) if v.startswith('.')) and 'keyword-value' not in args: ret = length_expand(css_dict, args['property-name'], args.get('type-value', ''), args.get('type-name', ''), options) return ret elif 'type-value' in args: return str(args['type-value']) return args.get('keyword-value', '')
def generate_result_object(hayaku): # Trying to substitute abbreviation with aliased one, # should be placed somewhere else if isinstance(hayaku, dict): hayaku['abbr'] = hayaku['options'].get('aliases').get(hayaku.get('abbr'), hayaku.get('abbr')).replace(': ', ':') args = extract(hayaku) # Not that proper check for only-property with fallback, # should be inside `extract`, couldn't do it properly. if not args and ':' in hayaku.get('abbr', ''): abbr = hayaku.get('abbr') colon_index = abbr.index(':') + 1 hayaku['abbr'] = abbr[:colon_index] args = extract(hayaku) args['keyword-value'] = abbr[colon_index:] if not args: return None options = {} if isinstance(hayaku, dict): options = hayaku.get('options') value = expand_value(args, options.get('dict'), options) if value is None: return if value.startswith('[') and value.endswith(']'): value = False result = { 'abbr': args.get('abbr'), 'type': options.get('dict', {}).get(args['property-name'], {}).get('type', 'property'), 'property': args.get('property-name'), 'value': value } if isinstance(hayaku, dict) and hayaku.get('clipboard'): result['clipboard'] = hayaku.get('clipboard') if args.get('no-unprefixed-property'): result['no-unprefixed-property'] = True if args.get('prefixes'): result['prefixes'] = args.get('prefixes', []) if args.get('important'): result['important'] = True if result.get('value') == '#' or not result.get('value'): result['value'] = { 'default': args.get('default-value',''), 'symbols': [] } possible_values = [val for prop, val in get_flat_css(options.get('dict'), include_commented=True) if prop == result.get('property')] if possible_values: units = [] keywords = [] for p_value in (v for v in possible_values if len(v) > 1): if p_value.startswith('.'): units.append(p_value[1:]) else: if p_value.startswith('<'): result['value']['symbols'].append(p_value) else: keywords.append(p_value) if units: result['value']['units'] = units if keywords: result['value']['keywords'] = keywords return result
def generate_snippet_parts(expanded, options={}): value = expanded.get('value') option_color_length = options.get('CSS_colors_length', '').lower() snippet_parts = { 'before': [], 'after': [], 'autovalues': '', } if isinstance(value, dict): snippet_parts['default'] = value.get('default', '') if not options.get('CSS_disable_postexpand', False): auto_values = [val for prop, val in get_flat_css(options.get('dict'), include_commented=True) if prop == expanded.get('property')] if value.get('keywords'): values_splitted = split_for_snippet(value.get('keywords'), remove_possible_colors=(value.get('colors'))) snippet_values = '' for index in range(0,len(values_splitted[0])): snippet_values += ''.join([ '${1/^\s*', values_splitted[0][index], '.*/', values_splitted[1][index], '/m}', ]) snippet_parts['autovalues'] += snippet_values if value.get('units') and not '<color_values>' in value.get('symbols'): snippet_units = '' units_splitted = split_for_snippet(value.get('units'), 4) snippet_parts['before'].append({ "match": "%$", "insert": "100" }) # If there can be `number` in value, don't add `em` automatically optional_unit_for_snippet = '(?2:(?3::0)em:px)' if '<number>' in value.get('symbols') and not options.get('CSS_units_for_unitless_numbers'): optional_unit_for_snippet = '(?2:(?3::0):)' snippet_units = ''.join([ '${1/^\s*((?!0$)(?=.)[\d\-]*(\.)?(\d+)?((?=.)', units_splitted[0][0], ')?$)?.*/(?4:', units_splitted[1][0], ':(?1:' + optional_unit_for_snippet + '))/m}', ]) snippet_parts['autovalues'] += snippet_units # Adding snippets for colors if '<color_values>' in value.get('symbols'): # Insert hash and doubling letters snippet_parts['before'].append({ "match": "([0-9a-fA-F]{1,6}|[0-9a-fA-F]{3,6}\s*(!\w*\s*)?)$", "insert": "#" }) # Different handling based on color_length setting if option_color_length in ('short' 'shorthand'): snippet_parts['after'].append({ "match": "#?((?<firstFoundColorChar>[0-9a-fA-F])(?:(\g{firstFoundColorChar})|[0-9a-fA-F])?)$", "insert": "(?1:(?3:($2):$1$1))" }) elif option_color_length in ('long' 'longhand'): snippet_parts['after'].append({ "match": "#?((?<firstFoundColorChar>[0-9a-fA-F])\g{firstFoundColorChar}\g{firstFoundColorChar})$", "insert": "(?1:$1)" }) snippet_parts['after'].append({ "match": "#?([0-9a-fA-F]([0-9a-fA-F])?)$", "insert": "(?1:(?2:($1$1):$1$1$1$1$1)" }) else: snippet_parts['after'].append({ "match": "#?([0-9a-fA-F]{1,2})$", "insert": "(?1:$1$1)" }) # Insert `rgba` thingies snippet_parts['before'].append({ "match": "(\d{1,3}%?),(\.)?.*$", "insert": "rgba\((?2:$1,$1,)" }) snippet_parts['after'].append({ "match": "(\d{1,3}%?),(\.)?(.+)?$", "insert": "(?2:(?3::5):(?3::$1,$1,1))\)" }) # Getting the value from the clipboard # TODO: Move to the whole clipboard2default function check_clipboard_for_color = COMPLEX_COLOR_REGEX.match(expanded.get('clipboard')) if check_clipboard_for_color and 'colors' in options.get('CSS_clipboard_defaults'): snippet_parts['default'] = check_clipboard_for_color.group(1) if COLOR_WO_HASH_REGEX.match(snippet_parts['default']): snippet_parts['default'] = '#' + snippet_parts['default'] if '<url>' in value.get('symbols'): # TODO: move this out of `if not value`, # so we could use it for found `url()` values quote_symbol = '' if options.get('CSS_syntax_url_quotes'): quote_symbol = options.get('CSS_syntax_quote_symbol') snippet_parts['before'].append({ "match": "[^\s]+\.(jpg|jpeg|gif|png)$", "insert": "url\(" + quote_symbol }) snippet_parts['after'].append({ "match": "[^\s]+\.(jpg|jpeg|gif|png)$", "insert": quote_symbol + "\)" }) check_clipboard_for_image = IMAGE_REGEX.match(expanded.get('clipboard')) if check_clipboard_for_image and 'images' in options.get('CSS_clipboard_defaults'): quote_symbol = '' if options.get('CSS_syntax_url_quotes'): quote_symbol = options.get('CSS_syntax_quote_symbol') snippet_parts['default'] = 'url(' + quote_symbol + check_clipboard_for_image.group(1) + quote_symbol + ')' return snippet_parts
def extract(hayaku): if isinstance(hayaku, dict): s1 = hayaku.get('abbr') css_dict = hayaku.get('options').get('dict') css_aliases = hayaku.get('options').get('aliases') else: s1 = hayaku css_dict, css_aliases = get_css_dict() """В зависимости от найденных компонент в аббревиатуре применяет функцию extract""" prop_iter = [] parts = segmentation(s1) abbr_value = False if 'property-name' in parts: if parts['important']: s1 = s1[:-1] if s1[-1] != ':' and s1 != parts['property-name']: abbr_value = True if 'color' in parts: prop_iter.extend(prop for prop, val in get_flat_css(css_dict) if val == '<color_values>') if isinstance(parts.get('type-value'), int): prop_iter.extend(prop for prop, val in get_flat_css(css_dict) if val == '<integer>') if isinstance(parts.get('type-value'), float): # TODO: добавить deg, grad, time prop_iter.extend(prop for prop, val in get_flat_css(css_dict) if val in ('<length>', '<number>', 'percentage')) # TODO: проверить, всегда ли эта переменная нужна для следующих условий all_properties = get_all_properties(css_dict) if 'keyword-value' in parts and not parts['keyword-value']: prop_iter.extend(all_properties) if 'keyword-value' in parts: prop_iter.extend( prop_value(parts['property-name'], parts['keyword-value'], all_properties)) elif 'color' not in parts or 'type-value' in parts: prop_iter.extend(all_properties) if not parts or not (parts.get('property-name', '') or parts.get('property-value', '')): return abbr = ' '.join([ parts.get('property-name', '') or parts.get('property-value', ''), parts.get('keyword-value', ''), ]) abbr = abbr.strip() if not css_aliases.get(s1): abbr = css_aliases.get(abbr, abbr) if abbr[-1] == ':': abbr = abbr[:-1] starts_properties = [] # todo: переделать механизм PAIRS # надо вынести константы в css-dict # по две буквы (bd, bg, ba) pair = None for alias in css_aliases: if (alias.endswith('...')) and abbr.startswith(alias[:-3]): pair = css_aliases.get(alias) break if pair is not None: starts_properties = [ prop for prop in prop_iter if prop.startswith(pair) and sub_string(prop, abbr) ] if not starts_properties: starts_properties = [ prop for prop in prop_iter if prop[0] == abbr[0] and sub_string(prop, abbr) ] if 'type-value' in parts or ('keyword-value' in parts and parts['keyword-value'] == ''): starts_properties = [i for i in starts_properties if ' ' not in i] property_ = hayaku_extract(abbr, starts_properties, PRIORITY_PROPERTIES, string_score) property_, value = property_.split(' ') if ' ' in property_ else ( property_, None) # print property_, value if not property_: return {} parts['property-name'] = property_ if value is not None: parts['keyword-value'] = value # Проверка соответствия свойства и значения allow_values = [ val for prop, val in get_flat_css(css_dict) if prop == parts['property-name'] ] if 'color' in parts and '<color_values>' not in allow_values: del parts['color'] if 'type-value' in parts and not any( (t in allow_values) for t in ['<integer>', 'percentage', '<length>', '<number>', '<alphavalue>']): del parts['type-value'] if 'keyword-value' in parts and parts['keyword-value'] not in allow_values: del parts['keyword-value'] if all([ 'keyword-value' not in parts, 'type-value' not in parts, 'color' not in parts, ]) and abbr_value: return {} # Добавить значение по-умолчанию if parts['property-name'] in css_dict: default_value = css_defaults(parts['property-name'], css_dict) if default_value is not None: parts['default-value'] = default_value obj = css_dict[parts['property-name']] if 'prefixes' in obj: parts['prefixes'] = obj['prefixes'] if 'no-unprefixed-property' in obj: parts['no-unprefixed-property'] = obj['no-unprefixed-property'] if parts['abbr'] == parts.get('property-value'): del parts['property-value'] return parts
def generate_result_object(hayaku): # Trying to substitute abbreviation with aliased one, # should be placed somewhere else if isinstance(hayaku, dict): hayaku['abbr'] = hayaku['options'].get('aliases').get( hayaku.get('abbr'), hayaku.get('abbr')).replace(': ', ':') args = extract(hayaku) # Not that proper check for only-property with fallback, # should be inside `extract`, couldn't do it properly. if not args and ':' in hayaku.get('abbr', ''): abbr = hayaku.get('abbr') colon_index = abbr.index(':') + 1 hayaku['abbr'] = abbr[:colon_index] args = extract(hayaku) args['keyword-value'] = abbr[colon_index:] if not args: return None options = {} if isinstance(hayaku, dict): options = hayaku.get('options') value = expand_value(args, options.get('dict'), options) if value is None: return if value.startswith('[') and value.endswith(']'): value = False result = { 'abbr': args.get('abbr'), 'type': options.get('dict', {}).get(args['property-name'], {}).get('type', 'property'), 'property': args.get('property-name'), 'value': value } if isinstance(hayaku, dict) and hayaku.get('clipboard'): result['clipboard'] = hayaku.get('clipboard') if args.get('no-unprefixed-property'): result['no-unprefixed-property'] = True if args.get('prefixes'): result['prefixes'] = args.get('prefixes', []) if args.get('important'): result['important'] = True if result.get('value') == '#' or not result.get('value'): result['value'] = { 'default': args.get('default-value', ''), 'symbols': [] } possible_values = [ val for prop, val in get_flat_css(options.get('dict'), include_commented=True) if prop == result.get('property') ] if possible_values: units = [] keywords = [] for p_value in (v for v in possible_values if len(v) > 1): if p_value.startswith('.'): units.append(p_value[1:]) else: if p_value.startswith('<'): result['value']['symbols'].append(p_value) else: keywords.append(p_value) if units: result['value']['units'] = units if keywords: result['value']['keywords'] = keywords return result
def generate_snippet_parts(expanded, options={}): value = expanded.get('value') option_color_length = options.get('CSS_colors_length', '').lower() snippet_parts = { 'before': [], 'after': [], 'autovalues': '', } if isinstance(value, dict): snippet_parts['default'] = value.get('default', '') if not options.get('CSS_disable_postexpand', False): auto_values = [ val for prop, val in get_flat_css(options.get('dict'), include_commented=True) if prop == expanded.get('property') ] if value.get('keywords'): values_splitted = split_for_snippet( value.get('keywords'), remove_possible_colors=(value.get('colors'))) snippet_values = '' for index in range(0, len(values_splitted[0])): snippet_values += ''.join([ '${1/^\s*', values_splitted[0][index], '.*/', values_splitted[1][index], '/m}', ]) snippet_parts['autovalues'] += snippet_values if value.get( 'units') and not '<color_values>' in value.get('symbols'): snippet_units = '' units_splitted = split_for_snippet(value.get('units'), 4) snippet_parts['before'].append({ "match": "%$", "insert": "100" }) # If there can be `number` in value, don't add `em` automatically optional_unit_for_snippet = '(?2:(?3::0)em:px)' if '<number>' in value.get('symbols') and not options.get( 'CSS_units_for_unitless_numbers'): optional_unit_for_snippet = '(?2:(?3::0):)' snippet_units = ''.join([ '${1/^\s*((?!0$)(?=.)[\d\-]*(\.)?(\d+)?((?=.)', units_splitted[0][0], ')?$)?.*/(?4:', units_splitted[1][0], ':(?1:' + optional_unit_for_snippet + '))/m}', ]) snippet_parts['autovalues'] += snippet_units # Adding snippets for colors if '<color_values>' in value.get('symbols'): # Insert hash and doubling letters snippet_parts['before'].append({ "match": "([0-9a-fA-F]{1,6}|[0-9a-fA-F]{3,6}\s*(!\w*\s*)?)$", "insert": "#" }) # Different handling based on color_length setting if option_color_length in ('short' 'shorthand'): snippet_parts['after'].append({ "match": "#?((?<firstFoundColorChar>[0-9a-fA-F])(?:(\g{firstFoundColorChar})|[0-9a-fA-F])?)$", "insert": "(?1:(?3:($2):$1$1))" }) elif option_color_length in ('long' 'longhand'): snippet_parts['after'].append({ "match": "#?((?<firstFoundColorChar>[0-9a-fA-F])\g{firstFoundColorChar}\g{firstFoundColorChar})$", "insert": "(?1:$1)" }) snippet_parts['after'].append({ "match": "#?([0-9a-fA-F]([0-9a-fA-F])?)$", "insert": "(?1:(?2:($1$1):$1$1$1$1$1)" }) else: snippet_parts['after'].append({ "match": "#?([0-9a-fA-F]{1,2})$", "insert": "(?1:$1$1)" }) # Insert `rgba` thingies snippet_parts['before'].append({ "match": "(\d{1,3}%?),(\.)?.*$", "insert": "rgba\((?2:$1,$1,)" }) snippet_parts['after'].append({ "match": "(\d{1,3}%?),(\.)?(.+)?$", "insert": "(?2:(?3::5):(?3::$1,$1,1))\)" }) # Getting the value from the clipboard # TODO: Move to the whole clipboard2default function check_clipboard_for_color = COMPLEX_COLOR_REGEX.match( expanded.get('clipboard')) if check_clipboard_for_color and 'colors' in options.get( 'CSS_clipboard_defaults'): snippet_parts['default'] = check_clipboard_for_color.group( 1) if COLOR_WO_HASH_REGEX.match(snippet_parts['default']): snippet_parts[ 'default'] = '#' + snippet_parts['default'] if '<url>' in value.get('symbols'): # TODO: move this out of `if not value`, # so we could use it for found `url()` values quote_symbol = '' if options.get('CSS_syntax_url_quotes'): quote_symbol = options.get('CSS_syntax_quote_symbol') snippet_parts['before'].append({ "match": "[^\s]+\.(jpg|jpeg|gif|png)$", "insert": "url\(" + quote_symbol }) snippet_parts['after'].append({ "match": "[^\s]+\.(jpg|jpeg|gif|png)$", "insert": quote_symbol + "\)" }) check_clipboard_for_image = IMAGE_REGEX.match( expanded.get('clipboard')) if check_clipboard_for_image and 'images' in options.get( 'CSS_clipboard_defaults'): quote_symbol = '' if options.get('CSS_syntax_url_quotes'): quote_symbol = options.get('CSS_syntax_quote_symbol') snippet_parts[ 'default'] = 'url(' + quote_symbol + check_clipboard_for_image.group( 1) + quote_symbol + ')' return snippet_parts
def extract(hayaku): if isinstance(hayaku, dict): s1 = hayaku.get('abbr') css_dict = hayaku.get('options').get('dict') css_aliases = hayaku.get('options').get('aliases') else: s1 = hayaku css_dict, css_aliases = get_css_dict() """В зависимости от найденных компонент в аббревиатуре применяет функцию extract""" prop_iter = [] parts = segmentation(s1) abbr_value = False if 'property-name' in parts: if parts['important']: s1 = s1[:-1] if s1[-1] != ':' and s1 != parts['property-name']: abbr_value = True if 'color' in parts: prop_iter.extend(prop for prop, val in get_flat_css(css_dict) if val == '<color_values>') if isinstance(parts.get('type-value'), int): prop_iter.extend(prop for prop, val in get_flat_css(css_dict) if val == '<integer>') if isinstance(parts.get('type-value'), float): # TODO: добавить deg, grad, time prop_iter.extend(prop for prop, val in get_flat_css(css_dict) if val in ('<length>', '<number>', 'percentage')) # TODO: проверить, всегда ли эта переменная нужна для следующих условий all_properties = get_all_properties(css_dict) if 'keyword-value' in parts and not parts['keyword-value']: prop_iter.extend(all_properties) if 'keyword-value' in parts: prop_iter.extend(prop_value(parts['property-name'], parts['keyword-value'], all_properties)) elif 'color' not in parts or 'type-value' in parts: prop_iter.extend(all_properties) if not parts or not (parts.get('property-name', '') or parts.get('property-value', '')): return abbr = ' '.join([ parts.get('property-name', '') or parts.get('property-value', ''), parts.get('keyword-value', ''), ]) abbr = abbr.strip() if not css_aliases.get(s1): abbr = css_aliases.get(abbr, abbr) if abbr[-1] == ':': abbr = abbr[:-1] starts_properties = [] # todo: переделать механизм PAIRS # надо вынести константы в css-dict # по две буквы (bd, bg, ba) pair = None for alias in css_aliases: if (alias.endswith('...')) and abbr.startswith(alias[:-3]): pair = css_aliases.get(alias) break if pair is not None: starts_properties = [prop for prop in prop_iter if prop.startswith(pair) and sub_string(prop, abbr)] if not starts_properties: starts_properties = [prop for prop in prop_iter if prop[0] == abbr[0] and sub_string(prop, abbr)] if 'type-value' in parts or ('keyword-value' in parts and parts['keyword-value'] == ''): starts_properties = [i for i in starts_properties if ' ' not in i] property_ = hayaku_extract(abbr, starts_properties, PRIORITY_PROPERTIES, string_score) property_, value = property_.split(' ') if ' ' in property_ else (property_, None) # print property_, value if not property_: return {} parts['property-name'] = property_ if value is not None: parts['keyword-value'] = value # Проверка соответствия свойства и значения allow_values = [val for prop, val in get_flat_css(css_dict) if prop == parts['property-name']] if 'color' in parts and '<color_values>' not in allow_values: del parts['color'] if 'type-value' in parts and not any((t in allow_values) for t in ['<integer>', 'percentage', '<length>', '<number>', '<alphavalue>']): del parts['type-value'] if 'keyword-value' in parts and parts['keyword-value'] not in allow_values: del parts['keyword-value'] if all([ 'keyword-value' not in parts, 'type-value' not in parts, 'color' not in parts, ]) and abbr_value: return {} # Добавить значение по-умолчанию if parts['property-name'] in css_dict: default_value = css_defaults(parts['property-name'], css_dict) if default_value is not None: parts['default-value'] = default_value obj = css_dict[parts['property-name']] if 'prefixes' in obj: parts['prefixes'] = obj['prefixes'] if 'no-unprefixed-property' in obj: parts['no-unprefixed-property'] = obj['no-unprefixed-property'] if parts['abbr'] == parts.get('property-value'): del parts['property-value'] return parts