# this could read gcode firmware docs straight from their files
# but is presently copypaste
def parse_cmd(name, example, params, prefix='', suffix=''):
    cmd, name = name.split(' - ')
    exline, *comment = example.split(';',1)
    exline = exline.strip()
    exparts = exline.split(' ')
    assert exparts[0] == cmd
    exparts.pop(0)
    values = {
        value[0]: value[1:]
        for value in exparts
    }
    for param in params.split('\n\n'):
        param, pname = param.split('\n', 1)
        param = param.strip()
        if param[-1] in '0123456789':
            param, _ = param.rsplit(' ',1)
            param = param.strip()
        if param[0] == '[':
            param = param[1:-1]
        pchar = param[0]
        if pchar in values:
            if len(param) > 1 and param[1] == '<':
                pshort = param.strip()[2:-1]
                values[pchar] = f'PrinterValue({repr(pchar)}, {repr(pname)}, {repr(pshort)}, typical={values[pchar]})'
            else:
                values[pchar] = f'PrinterFlag({repr(pchar)}, {repr(pname)})'
    output = prefix+f'PrinterCmd({repr(name)}, {repr(cmd)}, doc={repr(comment[0].strip())},\n'
    for pname, value in values.items():
        output += prefix+f'\t{pname} = {value},\n'
    output += prefix+f')'+suffix + '\n'
    return output
def parse(varname, *texts):
    output = varname + ' = [\n'
    for text in texts:
        output += parse_cmd(*text.strip().split('\n',2), prefix='\t', suffix=',')
    output += ']\n'
    return output

def immed_cmds_code():
    return parse('immed_cmds', '''
M201 - Print Move Limits
M201 X500 Y500 Z100 E5000 ; sets maximum accelerations, mm/sec^2
[E<accel>] 
E axis max acceleration

[F<Hz>] 
Planner frequency limit (Requires XY_FREQUENCY_LIMIT)

[S<percent>]    
Planner XY frequency minimum speed percentage (Requires XY_FREQUENCY_LIMIT)

[T<index>]  
Target extruder (Requires DISTINCT_E_FACTORS)

[X<accel>]  
X axis max acceleration

[Y<accel>]  
Y axis max acceleration

[Z<accel>]  
Z axis max acceleration
''','''
M203 - Set Max Feedrate
M203 X500 Y500 Z10 E60 ; sets maximum feedrates, mm / sec
[E<units/s>]    
E axis max feedrate

[T<index>]  
Target extruder (Requires DISTINCT_E_FACTORS)

[X<units/s>]    
X axis max feedrate

[Y<units/s>]    
Y axis max feedrate

[Z<units/s>]    
Z axis max feedrate
''','''
M204 - Set Starting Acceleration
M204 P500 R1000 T500 ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2
[P<accel>]  
Printing acceleration. Used for moves that include extrusion (i.e., which employ the current tool).

[R<accel>]  
Retract acceleration. Used for extruder retraction moves.

[S<accel>]  
Legacy parameter for move acceleration. Set both printing and travel acceleration.

[T<accel>]  
Travel acceleration. Used for moves that include no extrusion.
''','''
M205 - Set Advanced Settings
M205 S0 T0 X8.00 Y8.00 Z0.40 E5.00 ; sets the minimum extruding and travel feed rate, mm/sec ; sets the jerk limits, mm/sec
[B<µs>] 
Minimum segment time (µs)

[E<jerk>]   
E max jerk (units/s)

[J<deviation>]  
Junction deviation (requires JUNCTION_DEVIATION)

[S<units/s>]    
Minimum feedrate for print moves (units/s)

[T<units/s>]    
Minimum feedrate for travel moves (units/s)

[X<jerk>]   
X max jerk (units/s)

[Y<jerk>]   
Y max jerk (units/s)

[Z<jerk>]   
Z max jerk (units/s)
''')
def delay_cmds_code():
    return parse('delay_cmds', '''
M106 - Set Fan Speed
M106 S128 ; fan duty cycle
[I<index>]  2.0.6   
Material preset index. Overrides S.

[P<index>]  
Fan index

[S<speed>]  
Speed, from 0 to 255. S255 provides 100% duty cycle; S128 produces 50%.

[T<secondary>]  
Secondary speed. Added in Marlin 1.1.7. (Requires EXTRA_FAN_SPEED)

M106 P<fan> T3-255 sets a secondary speed for <fan>.
M106 P<fan> T2 uses the set secondary speed.
M106 P<fan> T1 restores the previous fan speed.
''','''
M104 - Set Hotend Temperature
M104 S225 ; set temporary nozzle temp
[B<temp>]   
AUTOTEMP: The max auto-temperature.

[F<flag>]   
AUTOTEMP: Autotemp flag. Omit to disable autotemp.

[I<index>]  2.0.6   
Material preset index. Overrides S.

[S<temp>]   
Target temperature.
AUTOTEMP: the min auto-temperature.

[T<index>]  
Hotend index. If omitted, the currently active hotend will be used.
''','''
M140 - Set Bed Temperature
M140 S60 ; set final bed temp
[I<index>]  2.0.6   
Material preset index. Overrides S.

[S<temp>]   
Target temperature
''')
def wait_cmds_code():
    return parse('wait_cmds', '''
G4 - Dwell
G4 S30 ; allow partial nozzle warmup
[P<time(ms)>]   
Amount of time to dwell

[S<time(sec)>]  
Amount of time to dwell
''','''
M190 - Wait for Bed Temperature
M190 R60 ; wait for bed temp to stabilize
[I<index>]  2.0.6   
Material preset index. Overrides S.

[R<temp>]   
Target temperature (wait for cooling or heating).

[S<temp>]   
Target temperature (wait only when heating).
''','''
M109 - Wait for Hotend Temperature
M109 R210 ; wait for nozzle temp to stabilize
[B<temp>]   
With AUTOTEMP, the max auto-temperature.

[F<flag>]   
Autotemp flag. Omit to disable autotemp.

[I<index>]  2.0.6   
Material preset index. Overrides S.

[R<temp>]   
Target temperature (wait for cooling or heating).

[S<temp>]   
Target temperature (wait only when heating). Also AUTOTEMP: The min auto-temperature.

[T<index>]  
Hotend index. If omitted, the currently active hotend will be used.
''')
