| # Copyright 2020 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import collections |
| import functools |
| import itertools |
| import re |
| from typing import Dict, Iterable, Tuple |
| |
| import wayland_protocol_data_classes |
| |
| # Short aliases for typing |
| Interface = wayland_protocol_data_classes.Interface |
| Protocol = wayland_protocol_data_classes.Protocol |
| |
| |
| def split_for_words(x: str) -> Tuple[str, ...]: |
| """Split underscore_seperated identifiers into a component words.""" |
| return tuple(w.lower() for w in x.split('_')) |
| |
| |
| def kebab_case(x: str) -> str: |
| """Convert the input identifier to kebab-case""" |
| return '-'.join(split_for_words(x)) |
| |
| |
| def pascal_case(x: str) -> str: |
| """Convert the input identifier to PascalCase""" |
| return ''.join(w.title() for w in split_for_words(x)) |
| |
| |
| @functools.lru_cache(maxsize=None) |
| def get_base_human_readable_name_map( |
| protocols: Iterable[Protocol]) -> Dict[str, str]: |
| """Determines a mapping of each interface name to an identifier name.""" |
| |
| # Default to the full interface name as the identifier. |
| interface_identifiers = dict((interface.name, interface.name) |
| for protocol in protocols |
| for interface in protocol.interfaces) |
| |
| # Reserve the full interface names as identifiers, so nothing is |
| # ever shortened to another interface name. |
| used = set(interface_identifiers.keys()) |
| |
| def set_identifier_name_for_protocol(names: Iterable[str], |
| interface: Interface) -> None: |
| """Set the first unused name in |names| as the name for |interface|""" |
| for name in names: |
| if name not in used: |
| used.add(name) |
| interface_identifiers[interface.name] = name |
| return |
| |
| def set_identifier_names_for_interface( |
| interfaces: Iterable[Interface]) -> None: |
| """Try and set a shorter name for each interface""" |
| # For each interface in protocol, try and find a shorter name to use |
| # when representing instances of that interface. |
| for interface in interfaces: |
| name = interface.name |
| name_no_prefix = name.split('_', 1)[-1] |
| name_no_suffix = re.sub('_v\d+$', '', name) |
| name_no_prefix_or_suffix = re.sub(r'_v\d+$', '', name_no_prefix) |
| |
| set_identifier_name_for_protocol( |
| [name_no_prefix_or_suffix, name_no_prefix, name_no_suffix], |
| interface) |
| |
| def prioritize_interfaces( |
| interfaces: Iterable[Interface]) -> Tuple[Interface, ...]: |
| DEFAULT_STABLE_PRIORITY = 100 |
| DEFAULT_UNSTABLE_PRIORITY = 101 |
| UNSTABLE_PREFIX = 'z' |
| prefix_priorities = dict(wl_=0, |
| wp_=1, |
| xdg_=2, |
| zwl_=10, |
| zwp_=11, |
| zxdg_=12, |
| aura_=200, |
| cr_=201, |
| zaura_=202, |
| zcr_=203) |
| |
| interfaces_by_priority = collections.defaultdict(list) |
| |
| for protocol in protocols: |
| for interface in protocol.interfaces: |
| name = interface.name |
| priority = DEFAULT_STABLE_PRIORITY if not name.startswith( |
| UNSTABLE_PREFIX) else DEFAULT_UNSTABLE_PRIORITY |
| for prefix, prefix_priority in prefix_priorities.items(): |
| if name.startswith(prefix): |
| priority = prefix_priority |
| break |
| interfaces_by_priority[priority].append(interface) |
| |
| return tuple( |
| itertools.chain(*tuple(interfaces_by_priority[p] |
| for p in sorted(interfaces_by_priority)))) |
| |
| set_identifier_names_for_interface( |
| prioritize_interfaces( |
| tuple( |
| itertools.chain(*tuple(protocol.interfaces |
| for protocol in protocols))))) |
| return interface_identifiers |