vpype-gcode icon indicating copy to clipboard operation
vpype-gcode copied to clipboard

Permit vpype-gcode expression substitution into patterns.

Open tatarize opened this issue 3 years ago • 5 comments

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.

tatarize avatar Oct 01 '22 08:10 tatarize

  • 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.

tatarize avatar Oct 01 '22 08:10 tatarize

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

tyehle avatar Oct 01 '22 16:10 tyehle

This would also let you do awesome stuff like

layer_join = "{'G01 X0 Y0\nM0 Change color' if layer_index == 2 else ''}"

tyehle avatar Oct 01 '22 16:10 tyehle

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.

tatarize avatar Oct 08 '22 11:10 tatarize

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

abey79 avatar Oct 30 '22 17:10 abey79