diff --git a/docs/syntax.md b/docs/syntax.md index de672847..17d6fcef 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -85,6 +85,10 @@ tweak: # optional tweaking of .gv output # loops loops: # every list item is itself a list of exactly two pins # on the connector that are to be shorted + + # optional tweaking of .gv output executed for each instance of this connector + tweak: # see below + ``` ## Cable attributes @@ -148,6 +152,9 @@ tweak: # optional tweaking of .gv output show_wirecount: # defaults to true show_wirenumbers: # defaults to true for cables; false for bundles + # optional tweaking of .gv output executed for each instance of this cable + tweak: # see below + ``` ## Connection sets @@ -446,6 +453,10 @@ Alternatively items can be added to just the BOM by putting them in the section # This feature is experimental and might change # or be removed in future versions. + placeholder: # Substring to be replaced with name of connector or + # cable in all strings below for tweak in any of those + # sections. Default value is the global placeholder. + override: # dict of .gv entries to override # Each entry is identified by its leading string # in lines beginning with a TAB character. diff --git a/src/wireviz/DataClasses.py b/src/wireviz/DataClasses.py index 5b4bb068..6127099a 100644 --- a/src/wireviz/DataClasses.py +++ b/src/wireviz/DataClasses.py @@ -72,6 +72,7 @@ def __post_init__(self): @dataclass class Tweak: + placeholder: Optional[PlainText] = None override: Optional[Dict[Designator, Dict[str, Optional[str]]]] = None append: Union[str, List[str], None] = None @@ -164,11 +165,14 @@ class Connector: loops: List[List[Pin]] = field(default_factory=list) ignore_in_bom: bool = False additional_components: List[AdditionalComponent] = field(default_factory=list) + tweak: Optional[Tweak] = None def __post_init__(self) -> None: if isinstance(self.image, dict): self.image = Image(**self.image) + if self.tweak is not None: + self.tweak = Tweak(**self.tweak) self.ports_left = False self.ports_right = False @@ -274,11 +278,14 @@ class Cable: show_wirenumbers: Optional[bool] = None ignore_in_bom: bool = False additional_components: List[AdditionalComponent] = field(default_factory=list) + tweak: Optional[Tweak] = None def __post_init__(self) -> None: if isinstance(self.image, dict): self.image = Image(**self.image) + if self.tweak is not None: + self.tweak = Tweak(**self.tweak) if isinstance(self.gauge, str): # gauge and unit specified try: diff --git a/src/wireviz/Harness.py b/src/wireviz/Harness.py index 30468a6a..f2cb16ea 100644 --- a/src/wireviz/Harness.py +++ b/src/wireviz/Harness.py @@ -29,6 +29,7 @@ component_table_entry, generate_bom, get_additional_component_table, + make_list, pn_info_string, ) from wireviz.wv_colors import get_color_hex, translate_color @@ -78,12 +79,41 @@ def __post_init__(self): self._bom = [] # Internal Cache for generated bom self.additional_bom_items = [] + def join_tweak(self, node: Union[Connector, Cable]) -> None: + """Join node.tweak with self.tweak after replacing placeholders.""" + if node.tweak: + ph = node.tweak.placeholder + if ph is None: + ph = self.tweak.placeholder + # Create function rph() to replace placeholder with node name. + rph = (lambda s: s.replace(ph, node.name)) if ph else lambda s: s + n_override = node.tweak.override or {} + s_override = self.tweak.override or {} + for id, n_dict in n_override.items(): + id = rph(id) + s_dict = s_override.get(id, {}) + for k, v in n_dict.items(): + k = rph(k) + v = rph(v) + if k in s_dict and v != s_dict[k]: + ValueError( + f"{node.name}.tweak.override.{id}.{k} conflicts with another" + ) + s_dict[k] = v + s_override[id] = s_dict + self.tweak.override = s_override + self.tweak.append = make_list(self.tweak.append) + [ + rph(v) for v in make_list(node.tweak.append) + ] + def add_connector(self, name: str, *args, **kwargs) -> None: check_old(f"Connector '{name}'", OLD_CONNECTOR_ATTR, kwargs) self.connectors[name] = Connector(name, *args, **kwargs) + self.join_tweak(self.connectors[name]) def add_cable(self, name: str, *args, **kwargs) -> None: self.cables[name] = Cable(name, *args, **kwargs) + self.join_tweak(self.cables[name]) def add_mate_pin(self, from_name, from_pin, to_name, to_pin, arrow_type) -> None: self.mates.append(MatePin(from_name, from_pin, to_name, to_pin, arrow_type))