Permit vpype-gcode expression substitution into patterns.
If, we, for example needed gcode that set some value 20mm over per layer_id currently there is no set of methods that would allow this.
So the template would have something like %layer_id*20*mm% and that would be substituted by the correct value.
- We could have some kind of "preamble" config in the TOML that could be basically arbitrary python code.
- We could be to reword/improve the -d option so that you can set arbitrary variable (drawback: untyped, so not ideal for int/float)
- We could add a -e, --execute option to feed code for the expression interpreter, which would make it very easy to set parameter value, e.g. -e "offset=10*cm". ... etc.
Breaking changes
Using expression substitution from vpype proper requires that any direct use of % must be %% to avoid parsing confusion.
-
I might not know vpype well enough to be the best at hacking it in. But, I assume we add in @pass_state to gwrite, then accept a state as first parameter. We can then take any line we have do segment = state.substitue(segment) though it seems like state would need to know our very local state variables like layer_num to allow them to do the math with them.
-
SubstitutionHelper looks to be coupled too tightly with state to just institute another version of that. So it somehow needs to chain in the local dictionaries with the sub but I don't see any way to inject that very easily.
*Also, it's not clear if it could be integrated the other way since you clearly have {} replacements for those values in places too if that could be done rather than the format thing it might be more useful.
Could also eval an fstring instead of using format_map to allow full python expressions within the curly braces.
>>> template = "{layer_id*20}mm"
>>> vars = {"layer_id": 2}
>>> eval("f'{}'".format(template), vars)
'40mm'
This would mean that you couldn't put a single quote in the template string, but that could be mitigated somewhat by changing to f'''stuff'''. In that case only a ''' would cause problems in the template string
This would also let you do awesome stuff like
layer_join = "{'G01 X0 Y0\nM0 Change color' if layer_index == 2 else ''}"
I think @abey79 struck a balance here with the combination of safety and power.
layer_join = "{__import__('os').system('rm -rf /a-path-you-really-care-about')}"
I believe the vpype evaluation actually would permit some similar code. I'm just not well versed enough on it. He spent a while coming up with the formatting and my hopes for vpype-gcode is integration though that's seeming a bit far fetched, but I still try to adhere as best as I can to the regular API of vpype to facilitate that.
It randomly occurred to me that using the jinja templating engine might be a good avenue as well. In retrospect, possibly for vpype expression as well. Amongst the advantages I can think of:
- safety
- extensive documentation for the template-maker for free
- the doc/layer/line/segment nested loops could be reimplemented with the templating language, offering more customisability at the structural level (e.g. iterate multiple times over layers, sort according to another criterion, etc.)
- a small, but non-zero, chance that the user has previous experience with jinja