def check_color(color, data, context, echoerr): if color not in data['colors_config'].get('colors', {}) and color not in data['colors_config'].get('gradients', {}): echoerr(context='Error while checking highlight group in colorscheme (key {key})'.format(key=context_key(context)), problem='found unexistent color or gradient {0}'.format(color), problem_mark=color.mark) return True, False, True return True, False, False
def check_translated_group_name(group, data, context, echoerr): if group not in context[0][1].get('groups', {}): echoerr(context='Error while checking translated group in colorscheme (key {key})'.format(key=context_key(context)), problem='translated group {0} is not in main groups dictionary'.format(group), problem_mark=group.mark) return True, False, True return True, False, False
def check_segment_data_key(key, data, context, echoerr): ext = data['ext'] top_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) is_top_theme = (data['theme'] == top_theme_name) if is_top_theme: themes = data['ext_theme_configs'].values() else: themes = [context[0][1]] for theme in themes: for segments in theme.get('segments', {}).values(): found = False for segment in segments: if 'name' in segment: if key == segment['name']: found = True module = segment.get('module', theme.get('default_module', 'powerline.segments.' + ext)) if key == unicode(module) + '.' + unicode(segment['name']): found = True if found: break if found: break else: echoerr(context='Error while checking segment data', problem='found key {0} that cannot be associated with any segment'.format(key), problem_mark=key.mark) return True, False, True return True, False, False
def check_args_variant(segment, args, data, context, echoerr): argspec = getconfigargspec(segment) present_args = set(args) all_args = set(argspec.args) required_args = set(argspec.args[:-len(argspec.defaults)]) hadproblem = False if required_args - present_args: echoerr(context='Error while checking segment arguments (key {key})'.format(key=context_key(context)), context_mark=args.mark, problem='some of the required keys are missing: {0}'.format(list_sep.join(required_args - present_args))) hadproblem = True if not all_args >= present_args: echoerr(context='Error while checking segment arguments (key {key})'.format(key=context_key(context)), context_mark=args.mark, problem='found unknown keys: {0}'.format(list_sep.join(present_args - all_args)), problem_mark=next(iter(present_args - all_args)).mark) hadproblem = True if isinstance(segment, ThreadedSegment): for key in set(threaded_args_specs) & present_args: proceed, khadproblem = threaded_args_specs[key].match(args[key], args.mark, data, context + ((key, args[key]),), echoerr) if khadproblem: hadproblem = True if not proceed: return hadproblem return hadproblem
def check_segment_data_key(key, data, context, echoerr): ext = data["ext"] top_theme_name = data["main_config"].get("ext", {}).get(ext, {}).get("theme", None) is_top_theme = data["theme"] == top_theme_name if is_top_theme: themes = data["ext_theme_configs"].values() else: themes = [context[0][1]] for theme in themes: for segments in theme.get("segments", {}).values(): found = False for segment in segments: if "name" in segment: if key == segment["name"]: found = True module = segment.get("module", theme.get("default_module", "powerline.segments." + ext)) if key == unicode(module) + "." + unicode(segment["name"]): found = True if found: break if found: break else: echoerr( context="Error while checking segment data", problem="found key {0} that cannot be associated with any segment".format(key), problem_mark=key.mark, ) return True, False, True return True, False, False
def check_type(self, value, context_mark, data, context, echoerr, t): if type(value.value) is not t: echoerr(context=self.cmsg.format(key=context_key(context)), context_mark=context_mark, problem='must be a {0} instance'.format(t.__name__), problem_mark=value.mark) return False, True return True, False
def check_func(self, value, context_mark, data, context, echoerr, func, msg_func): proceed, echo, hadproblem = func(value, data, context, echoerr) if echo and hadproblem: echoerr(context=self.cmsg.format(key=context_key(context)), context_mark=context_mark, problem=msg_func(value), problem_mark=value.mark) return proceed, hadproblem
def match(self, value, context_mark=None, data=None, context=(), echoerr=echoerr): """Check that given value matches this specification :return: proceed, hadproblem. """ havemarks(value) proceed, hadproblem = self.match_checks(value, context_mark, data, context, echoerr) if proceed: if self.keys or self.uspecs: for key, vali in self.keys.items(): valspec = self.specs[vali] if key in value: proceed, mhadproblem = valspec.match( value[key], value.mark, data, context.enter_key(value, key), echoerr ) if mhadproblem: hadproblem = True if not proceed: return False, hadproblem else: if not valspec.isoptional: hadproblem = True echoerr( context=self.cmsg.format(key=context.key), context_mark=None, problem="required key is missing: {0}".format(key), problem_mark=value.mark, ) for key in value.keys(): havemarks(key) if key not in self.keys: for keyfunc, vali in self.uspecs: valspec = self.specs[vali] if isinstance(keyfunc, int): spec = self.specs[keyfunc] proceed, khadproblem = spec.match(key, context_mark, data, context, echoerr) else: proceed, khadproblem = keyfunc(key, data, context, echoerr) if khadproblem: hadproblem = True if proceed: proceed, vhadproblem = valspec.match( value[key], value.mark, data, context.enter_key(value, key), echoerr ) if vhadproblem: hadproblem = True break else: hadproblem = True if self.ufailmsg: echoerr( context=self.cmsg.format(key=context.key), context_mark=None, problem=self.ufailmsg(key), problem_mark=key.mark, ) return True, hadproblem
def check_highlight_group(hl_group, data, context, echoerr): r = hl_exists(hl_group, data, context, echoerr) if r: echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( hl_group, list_sep.join(r)), problem_mark=hl_group.mark) return True, False, True return True, False, False
def check_highlight_group(hl_group, data, context, echoerr): r = hl_exists(hl_group, data, context, echoerr) if r: echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( hl_group, ', '.join(r)), problem_mark=hl_group.mark) return True, False, True return True, False, False
def check_color(color, data, context, echoerr): if color not in data["colors_config"].get("colors", {}) and color not in data["colors_config"].get("gradients", {}): echoerr( context="Error while checking highlight group in colorscheme (key {key})".format(key=context_key(context)), problem="found unexistent color or gradient {0}".format(color), problem_mark=color.mark, ) return True, False, True return True, False, False
def check_segment_module(module, data, context, echoerr): with WithPath(data['import_paths']): try: __import__(unicode(module)) except ImportError: echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), problem='failed to import module {0}'.format(module), problem_mark=module.mark) return True, False, True return True, False, False
def check_type(self, value, context_mark, data, context, echoerr, t): if type(value.value) is not t: echoerr( context=self.cmsg.format(key=context_key(context)), context_mark=context_mark, problem="{0!r} must be a {1} instance, not {2}".format(value, t.__name__, type(value.value).__name__), problem_mark=value.mark, ) return False, True return True, False
def check_config(d, theme, data, context, echoerr): if len(context) == 4: ext = context[-2][0] else: # local_themes ext = context[-3][0] if ext not in data['configs']['themes'] or theme not in data['configs']['themes'][ext]: echoerr(context='Error while loading {0} from {1} extension configuration'.format(d[:-1], ext), problem='failed to find configuration file themes/{0}/{1}.json'.format(ext, theme), problem_mark=theme.mark) return True, False, True return True, False, False
def check_config(d, theme, data, context, echoerr): if len(context) == 4: ext = context[-2][0] else: # local_themes ext = context[-3][0] if ext not in data['configs'][d] or theme not in data['configs'][d][ext]: echoerr(context='Error while loading {0} from {1} extension configuration'.format(d[:-1], ext), problem='failed to find configuration file {0}/{1}/{2}.json'.format(d, ext, theme), problem_mark=theme.mark) return True, False, True return True, False, False
def check_type(self, value, context_mark, data, context, echoerr, types): if type(value.value) not in types: echoerr(context=self.cmsg.format(key=context_key(context)), context_mark=context_mark, problem='{0!r} must be a {1} instance, not {2}'.format( value, list_sep.join((t.__name__ for t in types)), type(value.value).__name__ ), problem_mark=value.mark) return False, True return True, False
def check_ext(ext, data, context, echoerr): hadsomedirs = False hadproblem = False for subdir in ('themes', 'colorschemes'): if ext not in data['configs'][subdir]: hadproblem = True echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='{0} configuration does not exist'.format(subdir)) else: hadsomedirs = True return hadsomedirs, hadproblem
def check_ext(ext, data, context, echoerr): hadsomedirs = False hadproblem = False for subdir in ("themes", "colorschemes"): if ext not in data["configs"][subdir]: hadproblem = True echoerr( context="Error while loading {0} extension configuration".format(ext), context_mark=ext.mark, problem="{0} configuration does not exist".format(subdir), ) else: hadsomedirs = True return hadsomedirs, hadproblem
def check_printable(self, value, context_mark, data, context, echoerr, _): '''Check that given unicode string contains only printable characters ''' hadproblem = False for match in NON_PRINTABLE_RE.finditer(value): hadproblem = True echoerr( context=self.cmsg.format(key=context.key), context_mark=value.mark, problem= 'found not printable character U+{0:04x} in a configuration string' .format(ord(match.group(0))), problem_mark=value.mark.advance_string(match.start() + 1)) return True, hadproblem
def check_matcher_func(ext, match_name, data, context, echoerr): import_paths = [os.path.expanduser(path) for path in context[0][1].get('common', {}).get('paths', [])] match_module, separator, match_function = match_name.rpartition('.') if not separator: match_module = 'powerline.matchers.{0}'.format(ext) match_function = match_name with WithPath(import_paths): try: func = getattr(__import__(match_module, fromlist=[match_function]), unicode(match_function)) except ImportError: echoerr(context='Error while loading matcher functions', problem='failed to load module {0}'.format(match_module), problem_mark=match_name.mark) return True, True except AttributeError: echoerr(context='Error while loading matcher functions', problem='failed to load matcher function {0}'.format(match_function), problem_mark=match_name.mark) return True, True if not callable(func): echoerr(context='Error while loading matcher functions', problem='loaded "function" {0} is not callable'.format(match_function), problem_mark=match_name.mark) return True, True if hasattr(func, 'func_code') and hasattr(func.func_code, 'co_argcount'): if func.func_code.co_argcount != 1: echoerr(context='Error while loading matcher functions', problem='function {0} accepts {1} arguments instead of 1. Are you sure it is the proper function?'.format(match_function, func.func_code.co_argcount), problem_mark=match_name.mark) return True, False
def check_highlight_groups(hl_groups, data, context, echoerr): rs = [hl_exists(hl_group, data, context, echoerr) for hl_group in hl_groups] if all(rs): echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight groups list ({0}) with all groups not defined in some colorschemes'.format( list_sep.join((unicode(h) for h in hl_groups))), problem_mark=hl_groups.mark) for r, hl_group in zip(rs, hl_groups): echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( hl_group, list_sep.join(r)), problem_mark=hl_group.mark) return True, False, True return True, False, False
def check_config(d, theme, data, context, echoerr): if len(context) == 4: ext = context[-2][0] else: # local_themes ext = context[-3][0] if ext not in data["configs"][d] or theme not in data["configs"][d][ext]: echoerr( context="Error while loading {0} from {1} extension configuration".format(d[:-1], ext), problem="failed to find configuration file {0}/{1}/{2}.json".format(d, ext, theme), problem_mark=theme.mark, ) return True, False, True return True, False, False
def check_printable(self, value, context_mark, data, context, echoerr, _): '''Check that given unicode string contains only printable characters ''' hadproblem = False for match in NON_PRINTABLE_RE.finditer(value): hadproblem = True echoerr( context=self.cmsg.format(key=context.key), context_mark=value.mark, problem='found not printable character U+{0:04x} in a configuration string'.format( ord(match.group(0))), problem_mark=value.mark.advance_string(match.start() + 1) ) return True, hadproblem
def check_highlight_groups(hl_groups, data, context, echoerr): rs = [hl_exists(hl_group, data, context, echoerr) for hl_group in hl_groups] if all(rs): echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight groups list ({0}) with all groups not defined in some colorschemes'.format( ', '.join((unicode(h) for h in hl_groups))), problem_mark=hl_groups.mark) for r, hl_group in zip(rs, hl_groups): echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( hl_group, ', '.join(r)), problem_mark=hl_group.mark) return True, False, True return True, False, False
def match(self, value, context_mark=None, data=None, context=EMPTYTUPLE, echoerr=echoerr): proceed, hadproblem = self.match_checks(value, context_mark, data, context, echoerr) if proceed: if self.keys or self.uspecs: for key, vali in self.keys.items(): valspec = self.specs[vali] if key in value: proceed, mhadproblem = valspec.match( value[key], value.mark, data, context + ((key, value[key]),), echoerr ) if mhadproblem: hadproblem = True if not proceed: return False, hadproblem else: if not valspec.isoptional: hadproblem = True echoerr( context=self.cmsg.format(key=context_key(context)), context_mark=None, problem="required key is missing: {0}".format(key), problem_mark=value.mark, ) for key in value.keys(): if key not in self.keys: for keyfunc, vali in self.uspecs: valspec = self.specs[vali] if isinstance(keyfunc, int): spec = self.specs[keyfunc] proceed, khadproblem = spec.match(key, context_mark, data, context, echoerr) else: proceed, khadproblem = keyfunc(key, data, context, echoerr) if khadproblem: hadproblem = True if proceed: valspec.match(value[key], value.mark, data, context + ((key, value[key]),), echoerr) break else: hadproblem = True if self.ufailmsg: echoerr( context=self.cmsg.format(key=context_key(context)), context_mark=None, problem=self.ufailmsg(key), problem_mark=key.mark, ) return True, hadproblem
def hl_exists(hl_group, data, context, echoerr, allow_gradients=False): ext = data["ext"] if ext not in data["colorscheme_configs"]: # No colorschemes. Error was already reported, no need to report it # twice return [] r = [] for colorscheme, cconfig in data["colorscheme_configs"][ext].items(): if hl_group not in cconfig.get("groups", {}): r.append(colorscheme) elif not allow_gradients or allow_gradients == "force": group_config = cconfig["groups"][hl_group] hadgradient = False for ckey in ("fg", "bg"): color = group_config.get(ckey) if not color: # No color. Error was already reported. continue # Gradients are only allowed for function segments. Note that # whether *either* color or gradient exists should have been # already checked hascolor = color in data["colors_config"].get("colors", {}) hasgradient = color in data["colors_config"].get("gradients", {}) if hasgradient: hadgradient = True if allow_gradients is False and not hascolor and hasgradient: echoerr( context="Error while checking highlight group in theme (key {key})".format( key=context_key(context) ), context_mark=getattr(hl_group, "mark", None), problem="group {0} is using gradient {1} instead of a color".format(hl_group, color), problem_mark=color.mark, ) r.append(colorscheme) continue if allow_gradients == "force" and not hadgradient: echoerr( context="Error while checking highlight group in theme (key {key})".format( key=context_key(context) ), context_mark=getattr(hl_group, "mark", None), problem="group {0} should have at least one gradient color, but it has no".format(hl_group), problem_mark=group_config.mark, ) r.append(colorscheme) return r
def check_either(self, value, context_mark, data, context, echoerr, start, end): errs = [] def new_echoerr(*args, **kwargs): errs.append((args, kwargs)) hadproblem = False for spec in self.specs[start:end]: proceed, hadproblem = spec.match(value, value.mark, data, context, new_echoerr) if not proceed: break if not hadproblem: return True, False for args, kwargs in errs: echoerr(*args, **kwargs) return False, hadproblem
def check_ext(ext, data, context, echoerr): hadsomedirs = False hadproblem = False if ext not in data['lists']['exts']: hadproblem = True echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='extension configuration does not exist') else: for typ in ('themes', 'colorschemes'): if ext not in data['configs'][typ] and not data['configs']['top_' + typ]: hadproblem = True echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='{0} configuration does not exist'.format(typ)) else: hadsomedirs = True return hadsomedirs, hadproblem
def check_config(d, theme, data, context, echoerr): if len(context) == 4: ext = context[-2][0] else: # local_themes ext = context[-3][0] if ext not in data['lists']['exts']: echoerr(context='Error while loading {0} extension configuration'.format(ext), context_mark=ext.mark, problem='extension configuration does not exist') return True, False, True if ((ext not in data['configs'][d] or theme not in data['configs'][d][ext]) and theme not in data['configs']['top_' + d]): echoerr(context='Error while loading {0} from {1} extension configuration'.format(d[:-1], ext), problem='failed to find configuration file {0}/{1}/{2}.json'.format(d, ext, theme), problem_mark=theme.mark) return True, False, True return True, False, False
def check_args(get_segment_variants, args, data, context, echoerr): new_echoerr = DelayedEchoErr(echoerr) count = 0 hadproblem = False for segment in get_segment_variants(data, context, new_echoerr): count += 1 shadproblem = check_args_variant(segment, args, data, context, echoerr) if shadproblem: hadproblem = True if not count: hadproblem = True if new_echoerr: new_echoerr.echo_all() else: echoerr(context='Error while checking segment arguments (key {key})'.format(key=context_key(context)), context_mark=context[-2][1].mark, problem='no suitable segments found') return True, False, hadproblem
def check_list(self, value, context_mark, data, context, echoerr, item_func, msg_func): i = 0 hadproblem = False for item in value: if isinstance(item_func, int): spec = self.specs[item_func] proceed, fhadproblem = spec.match(item, value.mark, data, context + (('list item ' + unicode(i), item),), echoerr) else: proceed, echo, fhadproblem = item_func(item, data, context, echoerr) if echo and fhadproblem: echoerr(context=self.cmsg.format(key=context_key(context) + '/list item ' + unicode(i)), context_mark=value.mark, problem=msg_func(item), problem_mark=item.mark) if fhadproblem: hadproblem = True if not proceed: return proceed, hadproblem i += 1 return True, hadproblem
def check_type(self, value, context_mark, data, context, echoerr, types): '''Check that given value matches given type(s) :param tuple types: List of accepted types. Since :py:class:`Spec` is supposed to describe JSON values only ``dict``, ``list``, ``unicode``, ``bool``, ``float`` and ``NoneType`` types make any sense. :return: proceed, hadproblem. ''' havemarks(value) if type(value.value) not in types: echoerr(context=self.cmsg.format(key=context.key), context_mark=context_mark, problem='{0!r} must be a {1} instance, not {2}'.format( value, ', '.join((t.__name__ for t in types)), type(value.value).__name__), problem_mark=value.mark) return False, True return True, False
def match(self, value, context_mark=None, data=None, context=EMPTYTUPLE, echoerr=echoerr): proceed, hadproblem = self.match_checks(value, context_mark, data, context, echoerr) if proceed: if self.keys or self.uspecs: for key, vali in self.keys.items(): valspec = self.specs[vali] if key in value: proceed, mhadproblem = valspec.match(value[key], value.mark, data, context + ((key, value[key]),), echoerr) if mhadproblem: hadproblem = True if not proceed: return False, hadproblem else: if not valspec.isoptional: hadproblem = True echoerr(context=self.cmsg.format(key=context_key(context)), context_mark=None, problem='required key is missing: {0}'.format(key), problem_mark=value.mark) for key in value.keys(): if key not in self.keys: for keyfunc, vali in self.uspecs: valspec = self.specs[vali] if isinstance(keyfunc, int): spec = self.specs[keyfunc] proceed, khadproblem = spec.match(key, context_mark, data, context, echoerr) else: proceed, khadproblem = keyfunc(key, data, context, echoerr) if khadproblem: hadproblem = True if proceed: valspec.match(value[key], value.mark, data, context + ((key, value[key]),), echoerr) break else: hadproblem = True if self.ufailmsg: echoerr(context=self.cmsg.format(key=context_key(context)), context_mark=None, problem=self.ufailmsg(key), problem_mark=key.mark) return True, hadproblem
def check_list(self, value, context_mark, data, context, echoerr, item_func, msg_func): '''Check that each value in the list matches given specification :param function item_func: Callable like ``func`` from :py:meth:`Spec.check_func`. Unlike ``func`` this callable is called for each value in the list and may be a :py:class:`Spec` object index. :param func msg_func: Callable like ``msg_func`` from :py:meth:`Spec.check_func`. Should accept one problematic item and is not used for :py:class:`Spec` object indicies in ``item_func`` method. :return: proceed, hadproblem. ''' havemarks(value) i = 0 hadproblem = False for item in value: havemarks(item) if isinstance(item_func, int): spec = self.specs[item_func] proceed, fhadproblem = spec.match( item, value.mark, data, context.enter_item('list item ' + unicode(i), item), echoerr ) else: proceed, echo, fhadproblem = item_func(item, data, context, echoerr) if echo and fhadproblem: echoerr(context=self.cmsg.format(key=context.key + '/list item ' + unicode(i)), context_mark=value.mark, problem=msg_func(item), problem_mark=item.mark) if fhadproblem: hadproblem = True if not proceed: return proceed, hadproblem i += 1 return True, hadproblem
def import_segment(name, data, context, echoerr, module=None): if not module: module = context[-2][1].get('module', context[0][1].get('default_module', 'powerline.segments.' + data['ext'])) with WithPath(data['import_paths']): try: func = getattr(__import__(unicode(module), fromlist=[unicode(name)]), unicode(name)) except ImportError: echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), problem='failed to import module {0}'.format(module), problem_mark=module.mark) return None except AttributeError: echoerr(context='Error while loading segment function (key {key})'.format(key=context_key(context)), problem='failed to load function {0} from module {1}'.format(name, module), problem_mark=name.mark) return None if not callable(func): echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), problem='imported "function" {0} from module {1} is not callable'.format(name, module), problem_mark=module.mark) return None return func
def check_key_compatibility(segment, data, context, echoerr): segment_type = segment.get('type', 'function') if segment_type not in type_keys: echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), problem='found segment with unknown type {0}'.format(segment_type), problem_mark=segment_type.mark) return False, False, True keys = set(segment) if not ((keys - generic_keys) < type_keys[segment_type]): unknown_keys = keys - generic_keys - type_keys[segment_type] echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), context_mark=context[-1][1].mark, problem='found keys not used with the current segment type: {0}'.format( ', '.join((unicode(key) for key in unknown_keys))), problem_mark=list(unknown_keys)[0].mark) return True, False, True if not (keys > required_keys[segment_type]): missing_keys = required_keys[segment_type] - keys echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), context_mark=context[-1][1].mark, problem='found missing required keys: {0}'.format( ', '.join((unicode(key) for key in missing_keys)))) return True, False, True return True, False, False
def hl_exists(hl_group, data, context, echoerr, allow_gradients=False): ext = data['ext'] if ext not in data['colorscheme_configs']: # No colorschemes. Error was already reported, no need to report it # twice return [] r = [] for colorscheme, cconfig in data['colorscheme_configs'][ext].items(): if hl_group not in cconfig.get('groups', {}): r.append(colorscheme) elif not allow_gradients or allow_gradients == 'force': group_config = cconfig['groups'][hl_group] hadgradient = False for ckey in ('fg', 'bg'): color = group_config.get(ckey) if not color: # No color. Error was already reported. continue # Gradients are only allowed for function segments. Note that # whether *either* color or gradient exists should have been # already checked hascolor = color in data['colors_config'].get('colors', {}) hasgradient = color in data['colors_config'].get('gradients', {}) if hasgradient: hadgradient = True if allow_gradients is False and not hascolor and hasgradient: echoerr(context='Error while checking highlight group in theme (key {key})'.format(key=context_key(context)), context_mark=getattr(hl_group, 'mark', None), problem='group {0} is using gradient {1} instead of a color'.format(hl_group, color), problem_mark=color.mark) r.append(colorscheme) continue if allow_gradients == 'force' and not hadgradient: echoerr(context='Error while checking highlight group in theme (key {key})'.format(key=context_key(context)), context_mark=getattr(hl_group, 'mark', None), problem='group {0} should have at least one gradient color, but it has no'.format(hl_group), problem_mark=group_config.mark) r.append(colorscheme) return r
def check_func(self, value, context_mark, data, context, echoerr, func, msg_func): '''Check value using given function :param function func: Callable that should accept four positional parameters: #. checked value, #. ``data`` parameter with arbitrary data (supplied by top-level caller), #. current context and #. function used for echoing errors. This callable should return three values: #. determines whether ``check_func`` caller should proceed calling other checks, #. determines whether ``check_func`` should echo error on its own (it should be set to False if ``func`` echoes error itself) and #. determines whether function has found some errors in the checked value. :param function msg_func: Callable that takes checked value as the only positional parameter and returns a string that describes the problem. Only useful for small checker functions since it is ignored when second returned value is false. :return: proceed, hadproblem. ''' havemarks(value) proceed, echo, hadproblem = func(value, data, context, echoerr) if echo and hadproblem: echoerr(context=self.cmsg.format(key=context.key), context_mark=context_mark, problem=msg_func(value), problem_mark=value.mark) return proceed, hadproblem
def check_key_compatibility(segment, data, context, echoerr): segment_type = segment.get('type', 'function') if segment_type not in type_keys: echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), problem='found segment with unknown type {0}'.format(segment_type), problem_mark=segment_type.mark) return False, False, True hadproblem = False keys = set(segment) if not ((keys - generic_keys) < type_keys[segment_type]): unknown_keys = keys - generic_keys - type_keys[segment_type] echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), context_mark=context[-1][1].mark, problem='found keys not used with the current segment type: {0}'.format( list_sep.join(unknown_keys)), problem_mark=list(unknown_keys)[0].mark) hadproblem = True if not (keys > required_keys[segment_type]): missing_keys = required_keys[segment_type] - keys echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), context_mark=context[-1][1].mark, problem='found missing required keys: {0}'.format( list_sep.join(missing_keys))) hadproblem = True if not (segment_type == 'function' or (keys & highlight_keys)): echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), context_mark=context[-1][1].mark, problem='found missing keys required to determine highlight group. Either highlight_group or name key must be present') hadproblem = True return True, False, hadproblem
def echoerr(self, *args, **kwargs): echoerr(*args, **kwargs) self.haserrors = True
def match(self, value, context_mark=None, data=None, context=(), echoerr=echoerr): '''Check that given value matches this specification :return: proceed, hadproblem. ''' havemarks(value) proceed, hadproblem = self.match_checks(value, context_mark, data, context, echoerr) if proceed: if self.keys or self.uspecs: for key, vali in self.keys.items(): valspec = self.specs[vali] if key in value: proceed, mhadproblem = valspec.match( value[key], value.mark, data, context.enter_key(value, key), echoerr ) if mhadproblem: hadproblem = True if not proceed: return False, hadproblem else: if not valspec.isoptional: hadproblem = True echoerr(context=self.cmsg.format(key=context.key), context_mark=None, problem='required key is missing: {0}'.format(key), problem_mark=value.mark) for key in value.keys(): havemarks(key) if key not in self.keys: for keyfunc, vali in self.uspecs: valspec = self.specs[vali] if isinstance(keyfunc, int): spec = self.specs[keyfunc] proceed, khadproblem = spec.match(key, context_mark, data, context, echoerr) else: proceed, khadproblem = keyfunc(key, data, context, echoerr) if khadproblem: hadproblem = True if proceed: proceed, vhadproblem = valspec.match( value[key], value.mark, data, context.enter_key(value, key), echoerr ) if vhadproblem: hadproblem = True break else: hadproblem = True if self.ufailmsg: echoerr(context=self.cmsg.format(key=context.key), context_mark=None, problem=self.ufailmsg(key), problem_mark=key.mark) return True, hadproblem
def check_segment_name(name, data, context, echoerr): ext = data['ext'] if context[-2][1].get('type', 'function') == 'function': func = import_segment(name, data, context, echoerr) if not func: return True, False, True hl_groups = [] divider_hl_group = None if func.__doc__: H_G_USED_STR = 'Highlight groups used: ' D_H_G_USED_STR = 'Divider highlight group used: ' for line in func.__doc__.split('\n'): if H_G_USED_STR in line: hl_groups.append(line[line.index(H_G_USED_STR) + len(H_G_USED_STR):]) elif D_H_G_USED_STR in line: divider_hl_group = line[line.index(D_H_G_USED_STR) + len(D_H_G_USED_STR) + 2:-3] hadproblem = False if divider_hl_group: r = hl_exists(divider_hl_group, data, context, echoerr, allow_gradients=True) if r: echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}\n(Group name was obtained from function documentation.)'.format( divider_hl_group, list_sep.join(r)), problem_mark=name.mark) hadproblem = True if hl_groups: greg = re.compile(r'``([^`]+)``( \(gradient\))?') hl_groups = [[greg.match(subs).groups() for subs in s.split(' or ')] for s in (list_sep.join(hl_groups)).split(', ')] for required_pack in hl_groups: rs = [hl_exists(hl_group, data, context, echoerr, allow_gradients=('force' if gradient else False)) for hl_group, gradient in required_pack] if all(rs): echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight groups list ({0}) with all groups not defined in some colorschemes\n(Group names were taken from function documentation.)'.format( list_sep.join((h[0] for h in required_pack))), problem_mark=name.mark) for r, h in zip(rs, required_pack): echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}'.format( h[0], list_sep.join(r))) hadproblem = True else: r = hl_exists(name, data, context, echoerr, allow_gradients=True) if r: echoerr(context='Error while checking theme (key {key})'.format(key=context_key(context)), problem='found highlight group {0} not defined in the following colorschemes: {1}\n(If not specified otherwise in documentation, highlight group for function segments\nis the same as the function name.)'.format( name, list_sep.join(r)), problem_mark=name.mark) hadproblem = True return True, False, hadproblem else: if name not in context[0][1].get('segment_data', {}): top_theme_name = data['main_config'].get('ext', {}).get(ext, {}).get('theme', None) if data['theme'] == top_theme_name: top_theme = {} else: top_theme = data['ext_theme_configs'].get(top_theme_name, {}) if name not in top_theme.get('segment_data', {}): echoerr(context='Error while checking segments (key {key})'.format(key=context_key(context)), problem='found useless use of name key (such name is not present in theme/segment_data)', problem_mark=name.mark) return True, False, False