Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Jinja-like attribute substitution syntax #254

Merged
merged 4 commits into from Apr 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev/demo-workspace
Submodule demo-workspace updated 1721 files
1,408 changes: 607 additions & 801 deletions dev/diagrams/attributes_system.dia

Large diffs are not rendered by default.

110 changes: 55 additions & 55 deletions dev/diagrams/svg/attributes_system.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified dev/doxygen/images/attributes_system.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 54 additions & 73 deletions dev/doxygen/pages/attributes_system.md
Expand Up @@ -24,32 +24,34 @@ by a dynamically determined text while the symbol is part of a schematic:
<th>Graphics Layer
<th>In schematics substituted by following value
<tr>
<td>`#NAME`
<td>`{{NAME}}`
<td>`sym_names`
<td>Designator of the symbol's component in a schematic (e.g. "R5")
<tr>
<td>`#VALUE`
<td>`{{VALUE}}`
<td>`sym_values`
<td>Most important attribute of the symbol's component
(e.g. "100nF" for a capacitor, or "LM358N" for an OpAmp)<br>
*Note: With which attribute's value `#VALUE` is substituted is
*Note: With which attribute's value `{{VALUE}}` is substituted is
controlled by the corresponding component, not by the symbol itself.*
<tr>
<td>`#PARTNUMBER`
<td>`{{PARTNUMBER}}`
<td>`sym_attributes`
<td>Part number of the linked device (e.g. "LM358N")<br>
*Note: Such arbitrary attributes should normally not be added to
symbols! Instead, the `#VALUE` attribute should be used in most cases.*
*Note: Such arbitrary attributes should normally not be added to symbols!
Instead, the `{{VALUE}}` attribute should be used in most cases.*
</table>

The `#NAME` and `#VALUE` are the most important attributes of a symbol, nearly
every symbol will have text items to display them in schematics. They also have
their own graphics layer, so it's possible to show or hide the names and values
of all symbols in a schematic by changing the visibility of these two layers.
The `{{NAME}}` and `{{VALUE}}` are the most important attributes of a symbol,
nearly every symbol will have text items to display them in schematics. They
also have their own graphics layer, so it's possible to show or hide the names
and values of all symbols in a schematic by changing the visibility of these two
layers.

For text items which display other attributes (e.g. `#PARTNUMBER`, `#RESISTANCE`
or `#FOOBAR`) the graphics layer `sym_attributes` should be used. There are no
more layers to further distinguish between different attributes.
For text items which display other attributes (e.g. `{{PARTNUMBER}}`,
`{{RESISTANCE}}` or `{{FOOBAR}}`) the graphics layer `sym_attributes` should be
used. There are no more layers to further distinguish between different
attributes.

Exactly the same system also applies to footprints, with the only exception that
different graphics layers are used (`top_names`, `bot_names`, `top_values`, ...).
Expand Down Expand Up @@ -90,15 +92,15 @@ Attributes can be defined at various objects, with different scopes:
If the value of an attribute needs to be determined for one specific purpose
(for example to substitute a text in a symbol), the lookup is done in a specific
order. The red arrows of the following diagram show how this order is defined.
It also lists all built-in attributes (the ones starting with a '#') and on
which scopes it is possible to add user-defined attributes.
It also lists all built-in attributes and on which scopes it is possible to add
user-defined attributes.

![Attributes System](attributes_system.png)


# Multiple Key Substitution {#doc_attributes_system_multiple_key_substitution}

Sometimes the `#VALUE` text in a symbol or footprint should be substituted by
Sometimes the `{{VALUE}}` text in a symbol or footprint should be substituted by
the most exact attribute of a component or device. For example a microcontroller
symbol in the schematic should show the exact part number of the corresponding
device (Prio. 1). But if no part number is available, the device name should be
Expand All @@ -107,47 +109,25 @@ assigned, the component name should be shown (Prio. 3). This table shows these
three cases for the [STM32F103C8T7TR](http://www.st.com/resource/en/datasheet/stm32f103c8.pdf):


| Prio. | Component Name | Device Name | Device Part Number | Desired Substitution of `#VALUE` |
|-------|----------------|----------------|--------------------|----------------------------------|
| 1 | "STM32F103C" | "STM32F103CxT" | "STM32F103C8T7TR" | "STM32F103C8T7TR" |
| 2 | "STM32F103C" | "STM32F103CxT" | N/A | "STM32F103CxT" |
| 3 | "STM32F103C" | N/A | N/A | "STM32F103C" |
| Prio. | Component Name | Device Name | Device Part Number | Desired Substitution of `{{VALUE}}` |
|-------|----------------|----------------|--------------------|-------------------------------------|
| 1 | "STM32F103C" | "STM32F103CxT" | "STM32F103C8T7TR" | "STM32F103C8T7TR" |
| 2 | "STM32F103C" | "STM32F103CxT" | N/A | "STM32F103CxT" |
| 3 | "STM32F103C" | N/A | N/A | "STM32F103C" |

To get this "best-match-attribute" behavior, the `#VALUE` attribute of a
component can be set to the value "#PARTNUMBER|DEVICE|COMPONENT". So the '|'
character after a key means that a fallback key is following if the first key
is not set to a non-empty value. As soon as the first value of the specified
To get this "best-match-attribute" behavior, the `{{VALUE}}` attribute of a
component can be set to the value "{{PARTNUMBER or DEVICE or COMPONENT}}". So
the 'or' keyword after a key means that a fallback key is following if the first
key is not set to a non-empty value. As soon as the first value of the specified
keys is not empty, all following keys are ignored.

Of course this system applies to arbitrary attributes, not only to `#VALUE`.
Of course this system applies to arbitrary attributes, not only to `{{VALUE}}`.


# Syntax {#doc_attributes_system_syntax}
# Allowed Characters {#doc_attributes_system_allowed_characters}

## Allowed Characters {#doc_attributes_system_allowed_characters}

Attribute keys must only consist of the characters 0-9, a-z, A-Z and '_'.
The first invalid character after a '#' is considered as the end of the key
(e.g. in the string "#FOO.BAR", only "#FOO" will be substituted).

In addition, the character '|', which is used for
@ref doc_attributes_system_multiple_key_substitution and
@ref doc_attributes_system_manual_end, has special functionality inside or at
the end of key names. Outside of keys, this character does not have a special
functionality, so it will not be substituted and does not require escaping.

## Manual End of Key {#doc_attributes_system_manual_end}

If the end of a key needs to be specified manually (e.g. to only substitute
"#FOO|BAR" in the string "#FOO|BAR42"), the key(s) must be followed by "||"
(i.e. "#FOO|BAR||42").

## Escaping {#doc_attributes_system_escaping}

To use the '#' character in a text item without the need for attribute
replacement, the character needs to be escaped by a second '#'. For example the
text "##FOOBAR##" will be rendered as "#FOOBAR#" without any attribute
substitution.
Attribute keys must only consist of the characters 0-9, a-z, A-Z and '_'. In
addition, key names must not start with a digit.


# Visibility in Schematics and Boards {#doc_attributes_system_visibility}
Expand All @@ -159,17 +139,18 @@ capacitor should show the value "100nF/50V" in the schematic, but only "100nF"
in the board because of the limited space.

By default, symbols and footprints show all the attributes which are contained
in a text item in their library elements (like `#NAME`, `#VALUE` and
`#PARTNUMBER` in the symbol above). But in schematics and boards, the user can
remove every single of these text items to hide specific attributes. Or to show
more attributes, new text items (with arbitrary values) can be added to symbols
and footprints. New text items are then added with some default properties
(layer, text size, position, ...) which the user needs to adjust afterwards.
in a text item in their library elements (like `{{NAME}}`, `{{VALUE}}` and
`{{PARTNUMBER}}` in the symbol above). But in schematics and boards, the user
can remove every single of these text items to hide specific attributes. Or to
show more attributes, new text items (with arbitrary values) can be added to
symbols and footprints. New text items are then added with some default
properties (layer, text size, position, ...) which the user needs to adjust
afterwards.

**Anyway, adding attributes other than `#NAME` and `#VALUE` to library symbols
and footprints should be used very rarely to keep symbols as clean and simple as
possible. For the most important attributes, the `#VALUE` text item should be
used.**
**Anyway, adding attributes other than `{{NAME}}` and `{{VALUE}}` to library
symbols and footprints should be used very rarely to keep them as clean and
simple as possible. For the most important attributes, the `{{VALUE}}` text item
should be used.**


# Example Use-Cases {#doc_attributes_system_example_usecases}
Expand All @@ -187,19 +168,19 @@ Here are some examples how the attribute system works for standard use-cases:
<tr>
<td rowspan="5">Resistor<br>Capacitor<br>Inductor
<td rowspan="4">@image html resistor_symbol.png
<td>#VALUE <td colspan="2">"#RESISTANCE #TOLERANCE #POWER"
<td>{{VALUE}}<td colspan="2">"{{RESISTANCE}} {{TOLERANCE}} {{POWER}}"
<td rowspan="4">@image html resistor_schematic.png
<tr><td>#RESISTANCE <td><td>"10Ω"
<tr><td>#TOLERANCE <td><td>"1%"
<tr><td>#POWER <td><td>"5W"
<tr><td>{{RESISTANCE}}<td><td>"10Ω"
<tr><td>{{TOLERANCE}}<td><td>"1%"
<tr><td>{POWER}}<td><td>"5W"
<tr>
<td rowspan="1">@image html resistor_footprint.png
<td>#VALUE <td colspan="2">"#RESISTANCE"
<td>{{VALUE}}<td colspan="2">"{{RESISTANCE}}"
<td rowspan="1">@image html resistor_board.png
<tr>
<td rowspan="2">Diode<br>Transistor<br>OpAmp
<td rowspan="1">@image html diode_symbol.png
<td>#VALUE <td colspan="2">"#PARTNUMBER|DEVICE"
<td>{{VALUE}}<td colspan="2">"{{ PARTNUMBER or DEVICE }}"
<td rowspan="1">@image html diode_schematic.png
<tr>
<td rowspan="1">@image html diode_footprint.png
Expand All @@ -208,18 +189,18 @@ Here are some examples how the attribute system works for standard use-cases:
<tr>
<td rowspan="4">LED
<td rowspan="2">@image html led_symbol.png
<td>#VALUE <td colspan="2">\"#PARTNUMBER|DEVICE <br> #COLOR\"
<td>{{VALUE}} <td colspan="2">\"{{ PARTNUMBER or DEVICE }} <br> {{COLOR}}\"
<td rowspan="2">@image html led_schematic.png
<tr><td>#COLOR <td colspan="2">
<tr><td>{{COLOR}}<td colspan="2">
<tr>
<td rowspan="2">@image html led_footprint.png
<td>#VALUE <td colspan="2">"#COLOR"
<td>{{VALUE}}<td colspan="2">"{{COLOR}}"
<td rowspan="2">@image html led_board.png
<tr><td>#COLOR <td colspan="2">"RED"
<tr><td>{{COLOR}}<td colspan="2">"RED"
<tr>
<td rowspan="2">Connector
<td rowspan="1">@image html connector_symbol.png
<td>#VALUE <td colspan="2">"#PARTNUMBER|DEVICE"
<td>{{VALUE}}<td colspan="2">"{{ PARTNUMBER or DEVICE }}"
<td rowspan="1">@image html connector_schematic.png
<tr>
<td rowspan="1">@image html connector_footprint.png
Expand All @@ -228,7 +209,7 @@ Here are some examples how the attribute system works for standard use-cases:
<tr>
<td rowspan="2">Microcontroller
<td rowspan="1">@image html microcontroller_symbol.png
<td>#VALUE <td colspan="2">"#PARTNUMBER|DEVICE|COMPONENT"
<td>{{VALUE}}<td colspan="2">"{{ PARTNUMBER or DEVICE or COMPONENT }}"
<td rowspan="1">@image html microcontroller_schematic.png
<tr>
<td rowspan="1">@image html microcontroller_footprint.png
Expand Down
4 changes: 4 additions & 0 deletions libs/librepcb/common/attributes/attribute.cpp
Expand Up @@ -47,6 +47,10 @@ Attribute::Attribute(const SExpression& node) :
mUnit = mType->getUnitFromString(node.getValueByPath<QString>("unit", false));
mValue = node.getValueByPath<QString>("value", false);

// backward compatibility - remove this some time!
mValue.replace(QRegularExpression("#([_A-Za-z][_\\|0-9A-Za-z]*)"), "{{\\1}}");
mValue.replace(QRegularExpression("\\{\\{(\\w+)\\|(\\w+)\\}\\}"), "{{ \\1 or \\2 }}");

if (!checkAttributesValidity()) throw LogicError(__FILE__, __LINE__);
}

Expand Down
16 changes: 8 additions & 8 deletions libs/librepcb/common/attributes/attributeprovider.h
Expand Up @@ -36,12 +36,12 @@ namespace librepcb {

/**
* @brief The AttributeProvider class defines an interface for classes which provides
* some attributes which can be used as variables in texts (like "#NAME")
* some attributes which can be used as variables in texts (like "{{NAME}}")
*
* For example library symbols can contain text elements which contains variables, for
* example the most importants texts "#NAME" and "#VALUE". All these variables will be
* parsed and replaced with their values when such a text is displayed in a schematic of a
* project.
* example the most importants texts "{{NAME}}" and "{{VALUE}}". All these variables will
* be parsed and replaced with their values when such a text is displayed in a schematic
* of a project.
*
* Please read the documentation about the @ref doc_attributes_system to get an idea how
* the @ref doc_attributes_system works in detail.
Expand All @@ -68,9 +68,9 @@ class AttributeProvider
virtual ~AttributeProvider() noexcept {}

/**
* @brief Get the value of an attribute which can be used in texts (like "#NAME")
* @brief Get the value of an attribute which can be used in texts (like "{{NAME}}")
*
* @param key The attribute key name (e.g. "NAME" in "#NAME").
* @param key The attribute key name (e.g. "NAME" in "{{NAME}}").
*
* @return The value of the specified attribute (empty if attribute not found)
*/
Expand All @@ -79,7 +79,7 @@ class AttributeProvider
/**
* @brief Get the value of a user defined attribute (if available)
*
* @param key The attribute name (e.g. "NAME" for "#NAME")
* @param key The attribute name (e.g. "NAME" for "{{NAME}}")
*
* @return The value of the attribute (empty string if not found)
*/
Expand All @@ -91,7 +91,7 @@ class AttributeProvider
/**
* @brief Get the value of a built-in attribute (if available)
*
* @param key The attribute name (e.g. "NAME" for "#NAME")
* @param key The attribute name (e.g. "NAME" for "{{NAME}}")
*
* @return The value of the attribute (empty string if not found)
*/
Expand Down