|
33 | 33 | component_table_entry, |
34 | 34 | generate_bom, |
35 | 35 | get_additional_component_table, |
| 36 | + make_list, |
36 | 37 | pn_info_string, |
37 | 38 | ) |
38 | 39 | from wireviz.wv_colors import get_color_hex, translate_color |
@@ -132,9 +133,57 @@ def __post_init__(self): |
132 | 133 | def add_connector(self, name: str, *args, **kwargs) -> None: |
133 | 134 | check_old(f"Connector '{name}'", OLD_CONNECTOR_ATTR, kwargs) |
134 | 135 | self.connectors[name] = Connector(name, *args, **kwargs) |
| 136 | + self._extend_tweak(self.connectors[name]) |
135 | 137 |
|
136 | 138 | def add_cable(self, name: str, *args, **kwargs) -> None: |
137 | 139 | self.cables[name] = Cable(name, *args, **kwargs) |
| 140 | + self._extend_tweak(self.cables[name]) |
| 141 | + |
| 142 | + def _extend_tweak(self, node: Union[Connector, Cable]) -> None: |
| 143 | + """Fold ``node.tweak`` into ``self.tweak`` after substituting the |
| 144 | + node's name for the placeholder string. |
| 145 | +
|
| 146 | + Per-connector / per-cable ``tweak:`` entries let users author a |
| 147 | + single template and have its ``override`` keys / ``append`` lines |
| 148 | + rewritten with the actual designator at instantiation time. This |
| 149 | + is the only place the placeholder substitution happens — the |
| 150 | + global tweak is applied unchanged at graph emission time. |
| 151 | + """ |
| 152 | + if not node.tweak: |
| 153 | + return |
| 154 | + ph = node.tweak.placeholder |
| 155 | + # An empty string is a legal value to opt out of the global |
| 156 | + # placeholder; only None falls back. |
| 157 | + if ph is None: |
| 158 | + ph = self.tweak.placeholder |
| 159 | + # The replacement target may be None when an override deletes a |
| 160 | + # key (``key: null`` in YAML), so guard the str.replace call. |
| 161 | + if ph: |
| 162 | + rph = lambda s: s.replace(ph, node.name) if isinstance(s, str) else s |
| 163 | + else: |
| 164 | + rph = lambda s: s |
| 165 | + |
| 166 | + n_override = node.tweak.override or {} |
| 167 | + s_override = self.tweak.override or {} |
| 168 | + for ident, n_dict in n_override.items(): |
| 169 | + ident = rph(ident) |
| 170 | + s_dict = s_override.get(ident, {}) |
| 171 | + for k, v in n_dict.items(): |
| 172 | + k, v = rph(k), rph(v) |
| 173 | + if k in s_dict and v != s_dict[k]: |
| 174 | + raise ValueError( |
| 175 | + f"{node.name}.tweak.override.{ident}.{k} conflicts with another" |
| 176 | + ) |
| 177 | + s_dict[k] = v |
| 178 | + # Keep the empty dict rather than collapsing to None — the |
| 179 | + # graph-emission code (Harness.create_graph) expects values |
| 180 | + # in self.tweak.override to be dicts, not None. |
| 181 | + s_override[ident] = s_dict |
| 182 | + self.tweak.override = s_override or None |
| 183 | + self.tweak.append = ( |
| 184 | + make_list(self.tweak.append) |
| 185 | + + [rph(v) for v in make_list(node.tweak.append)] |
| 186 | + ) or None |
138 | 187 |
|
139 | 188 | def add_mate_pin(self, from_name, from_pin, to_name, to_pin, arrow_type) -> None: |
140 | 189 | self.mates.append(MatePin(from_name, from_pin, to_name, to_pin, arrow_type)) |
|
0 commit comments