{-# LANGUAGE OverloadedStrings #-}

module Draw.Plotting.GCode (
      GCode(..)
    , renderGCode
) where



import           Data.List
import           Data.Maybe
import qualified Data.Text.Lazy         as TL
import qualified Data.Text.Lazy.Builder as TL
import           Formatting             hiding (center)



-- | Raw GCode for penplotting.
data GCode
    = GComment TL.Text
    | GBlock [GCode]    -- ^ Group a couple of commands for easier reading.
    | F_Feedrate Double -- ^ Set the feedrate. Normally mm/min, but can be altered using G93, G94, G20, G21.
    | M0_Pause          -- ^ Pause and wait for user input

    | G00_LinearRapidMove (Maybe Double) (Maybe Double) (Maybe Double)                   -- ^ @G0 X Y Z@: Move as fast as possible
    | G01_LinearFeedrateMove (Maybe Double) (Maybe Double) (Maybe Double) (Maybe Double) -- ^ @G1 F X Y Z@: Move with specified feedrate
    | G02_ArcClockwise (Maybe Double) Double Double Double Double                        -- ^ @G2 F I J X Y@: Paint part of a circle, clockwise
    | G03_ArcCounterClockwise (Maybe Double) Double Double Double Double                 -- ^ @G3 F I J X Y@: Paint part of a circle, counterclockwise
    | G04_Dwell_ms Double -- ^ @G4 P@: wait a number of milliseconds.
    | G17_Plane_XY
    | G18_Plane_ZX
    | G19_Plane_YZ
    | G20_UseInches
    | G21_UseMm
    | G28_GotoPredefinedPosition (Maybe Double) (Maybe Double) (Maybe Double) -- ^ @G28 X Y Z@
    | G30_GotoPredefinedPosition (Maybe Double) (Maybe Double) (Maybe Double) -- ^ @G30 X Y Z@
    | G90_AbsoluteMovement -- ^ Move commands use coordinates relative to the origin
    | G91_RelativeMovement -- ^ Move commands use coordinates relative to the current position
    | G93_Feedrate_TravelInFractionOfMinute
    | G94_Feedrate_UnitsPerMinute
    deriving (GCode -> GCode -> Bool
(GCode -> GCode -> Bool) -> (GCode -> GCode -> Bool) -> Eq GCode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: GCode -> GCode -> Bool
== :: GCode -> GCode -> Bool
$c/= :: GCode -> GCode -> Bool
/= :: GCode -> GCode -> Bool
Eq, Eq GCode
Eq GCode
-> (GCode -> GCode -> Ordering)
-> (GCode -> GCode -> Bool)
-> (GCode -> GCode -> Bool)
-> (GCode -> GCode -> Bool)
-> (GCode -> GCode -> Bool)
-> (GCode -> GCode -> GCode)
-> (GCode -> GCode -> GCode)
-> Ord GCode
GCode -> GCode -> Bool
GCode -> GCode -> Ordering
GCode -> GCode -> GCode
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: GCode -> GCode -> Ordering
compare :: GCode -> GCode -> Ordering
$c< :: GCode -> GCode -> Bool
< :: GCode -> GCode -> Bool
$c<= :: GCode -> GCode -> Bool
<= :: GCode -> GCode -> Bool
$c> :: GCode -> GCode -> Bool
> :: GCode -> GCode -> Bool
$c>= :: GCode -> GCode -> Bool
>= :: GCode -> GCode -> Bool
$cmax :: GCode -> GCode -> GCode
max :: GCode -> GCode -> GCode
$cmin :: GCode -> GCode -> GCode
min :: GCode -> GCode -> GCode
Ord, Int -> GCode -> ShowS
[GCode] -> ShowS
GCode -> String
(Int -> GCode -> ShowS)
-> (GCode -> String) -> ([GCode] -> ShowS) -> Show GCode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> GCode -> ShowS
showsPrec :: Int -> GCode -> ShowS
$cshow :: GCode -> String
show :: GCode -> String
$cshowList :: [GCode] -> ShowS
showList :: [GCode] -> ShowS
Show)

-- | Convert 'GCode' to 'TL.Text', to be written to a file.
renderGCode :: [GCode] -> TL.Text
renderGCode :: [GCode] -> Text
renderGCode [GBlock [GCode]
xs] = [GCode] -> Text
renderGCode [GCode]
xs -- Remove indentation if it's a single top-level block
renderGCode [GCode]
xs = Builder -> Text
TL.toLazyText ([Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
"\n" ((GCode -> Builder) -> [GCode] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> GCode -> Builder
renderGcodeIndented Int
0) [GCode]
xs)))

renderGcodeIndented :: Int -> GCode -> TL.Builder
renderGcodeIndented :: Int -> GCode -> Builder
renderGcodeIndented !Int
level = \case
    GComment Text
comment -> Builder -> Builder
indent (Builder
"; " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
TL.fromLazyText Text
comment)
    GBlock [GCode]
content   -> [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse Builder
"\n" ((GCode -> Builder) -> [GCode] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> GCode -> Builder
renderGcodeIndented (Int
levelInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)) [GCode]
content))
    F_Feedrate Double
f     -> Builder -> Builder
indent (Format Builder (Double -> Builder) -> Double -> Builder
forall a. Format Builder a -> a
bformat (Format (Double -> Builder) (Double -> Builder)
"F " Format (Double -> Builder) (Double -> Builder)
-> Format Builder (Double -> Builder)
-> Format Builder (Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Format Builder (Double -> Builder)
forall r. Format r (Double -> r)
double) Double
f)
    GCode
M0_Pause         -> Builder -> Builder
indent Builder
"M0 (Pause/wait for user input)"

    G00_LinearRapidMove Maybe Double
x Maybe Double
y Maybe Double
z
        | (Maybe Double -> Bool) -> [Maybe Double] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Maybe Double -> Bool
forall a. Maybe a -> Bool
isNothing [Maybe Double
x,Maybe Double
y,Maybe Double
z] -> Text -> Builder
errorComment Text
"G0 requires at least one coordinate argument; omitting empty G0"
        | Bool
otherwise -> Builder -> Builder
indent (Format
  Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Maybe Double -> Maybe Double -> Maybe Double -> Builder
forall a. Format Builder a -> a
bformat (Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
"G0" Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Maybe Double -> Builder)
     (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"X" Format
  (Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Y" Format
  (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Z") Maybe Double
x Maybe Double
y Maybe Double
z)

    G01_LinearFeedrateMove Maybe Double
f Maybe Double
x Maybe Double
y Maybe Double
z
        | (Maybe Double -> Bool) -> [Maybe Double] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Maybe Double -> Bool
forall a. Maybe a -> Bool
isNothing [Maybe Double
x,Maybe Double
y,Maybe Double
z] -> Text -> Builder
errorComment Text
"G1 requires at least one coordinate argument; omitting empty G1"
        | Bool
otherwise -> Builder -> Builder
indent (Format
  Builder
  (Maybe Double
   -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Maybe Double
-> Maybe Double
-> Maybe Double
-> Maybe Double
-> Builder
forall a. Format Builder a -> a
bformat (Format
  (Maybe Double
   -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double
   -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
"G1" Format
  (Maybe Double
   -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double
   -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder
     (Maybe Double
      -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder
     (Maybe Double
      -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
     (Maybe Double
      -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"F" Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double
   -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder
     (Maybe Double
      -> Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Maybe Double -> Builder)
     (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"X" Format
  (Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Y" Format
  (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Z") Maybe Double
f Maybe Double
x Maybe Double
y Maybe Double
z)

    G02_ArcClockwise        Maybe Double
f Double
i Double
j Double
x Double
y -> Builder -> Builder
indent (Format
  Builder
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Maybe Double -> Double -> Double -> Double -> Double -> Builder
forall a. Format Builder a -> a
bformat (Format
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
"G2" Format
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Format
     Builder
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Format
     Builder
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Double -> Double -> Double -> Double -> Builder)
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"F" Format
  (Double -> Double -> Double -> Double -> Builder)
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Double -> Builder)
-> Format
     Builder
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Double -> Double -> Double -> Builder)
     (Double -> Double -> Double -> Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"X" Format
  (Double -> Double -> Double -> Builder)
  (Double -> Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Double -> Double -> Builder)
     (Double -> Double -> Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"Y" Format
  (Double -> Double -> Builder)
  (Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format (Double -> Builder) (Double -> Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"I" Format (Double -> Builder) (Double -> Double -> Builder)
-> Format Builder (Double -> Builder)
-> Format Builder (Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"J") Maybe Double
f Double
x Double
y Double
i Double
j)
    G03_ArcCounterClockwise Maybe Double
f Double
i Double
j Double
x Double
y -> Builder -> Builder
indent (Format
  Builder
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Maybe Double -> Double -> Double -> Double -> Double -> Builder
forall a. Format Builder a -> a
bformat (Format
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
"G3" Format
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Format
     Builder
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Format
     Builder
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Double -> Double -> Double -> Double -> Builder)
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"F" Format
  (Double -> Double -> Double -> Double -> Builder)
  (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Double -> Builder)
-> Format
     Builder
     (Maybe Double -> Double -> Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Double -> Double -> Double -> Builder)
     (Double -> Double -> Double -> Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"X" Format
  (Double -> Double -> Double -> Builder)
  (Double -> Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Double -> Double -> Builder)
     (Double -> Double -> Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"Y" Format
  (Double -> Double -> Builder)
  (Double -> Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Builder)
-> Format Builder (Double -> Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format (Double -> Builder) (Double -> Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"I" Format (Double -> Builder) (Double -> Double -> Builder)
-> Format Builder (Double -> Builder)
-> Format Builder (Double -> Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"J") Maybe Double
f Double
x Double
y Double
i Double
j)

    G04_Dwell_ms Double
s -> Builder -> Builder
indent (Format Builder (Double -> Builder) -> Double -> Builder
forall a. Format Builder a -> a
bformat (Format (Double -> Builder) (Double -> Builder)
"G4" Format (Double -> Builder) (Double -> Builder)
-> Format Builder (Double -> Builder)
-> Format Builder (Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required Builder
"P") Double
s)

    GCode
G17_Plane_XY -> Builder -> Builder
indent Builder
"G17 (Use XY plane)"
    GCode
G18_Plane_ZX -> Builder -> Builder
indent Builder
"G18 (Use ZX plane)"
    GCode
G19_Plane_YZ -> Builder -> Builder
indent Builder
"G19 (Use YZ plane)"
    GCode
G20_UseInches -> String -> Builder
forall a. HasCallStack => String -> a
error String
"Inches aren’t going to happen here, sorry."
    GCode
G21_UseMm -> Builder -> Builder
indent Builder
"G21 (Use mm)"

    G28_GotoPredefinedPosition Maybe Double
x Maybe Double
y Maybe Double
z -> Builder -> Builder
indent (Format
  Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Maybe Double -> Maybe Double -> Maybe Double -> Builder
forall a. Format Builder a -> a
bformat (Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
"G28" Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Maybe Double -> Builder)
     (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"X" Format
  (Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Y" Format
  (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Z") Maybe Double
x Maybe Double
y Maybe Double
z)
    G30_GotoPredefinedPosition Maybe Double
x Maybe Double
y Maybe Double
z -> Builder -> Builder
indent (Format
  Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Maybe Double -> Maybe Double -> Maybe Double -> Builder
forall a. Format Builder a -> a
bformat (Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
"G30" Format
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Maybe Double -> Builder)
     (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"X" Format
  (Maybe Double -> Maybe Double -> Builder)
  (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
-> Format
     Builder (Maybe Double -> Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder
-> Format
     (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Y" Format
  (Maybe Double -> Builder) (Maybe Double -> Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Builder)
-> Format Builder (Maybe Double -> Maybe Double -> Builder)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format Builder (Maybe Double -> Builder)
forall r. Builder -> Format r (Maybe Double -> r)
optional Builder
"Z") Maybe Double
x Maybe Double
y Maybe Double
z)

    GCode
G90_AbsoluteMovement -> Builder -> Builder
indent Builder
"G90 ;(G9(0) => abs(0)lute movement)"
    GCode
G91_RelativeMovement -> Builder -> Builder
indent Builder
"G91 ;(G9(1) => re(1)ative movement)"

    GCode
G93_Feedrate_TravelInFractionOfMinute -> Builder -> Builder
indent Builder
"G93 (feedrate is time to travel in fractions of one minute: F1000 = make the move in 60/1000 min)"
    GCode
G94_Feedrate_UnitsPerMinute -> Builder -> Builder
indent Builder
"G94 (feedrate is units per minute: F1000 = move at 1000 mm/min)"
  where
    indentation :: Text
indentation = Text
"    "
    indent :: Builder -> Builder
indent Builder
x = Text -> Builder
TL.fromLazyText (Int64 -> Text -> Text
TL.replicate (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
level) Text
indentation) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
x
    errorComment :: Text -> Builder
errorComment Text
msg = Int -> GCode -> Builder
renderGcodeIndented Int
level (Text -> GCode
GComment (Text
"ERROR: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
msg))

-- | Required number. Example: G02 requires an I parameter, hence @required "X"@.
required :: TL.Builder -> Format r (Double -> r)
required :: forall r. Builder -> Format r (Double -> r)
required Builder
x = Format (Double -> r) (Double -> r)
" " Format (Double -> r) (Double -> r)
-> Format r (Double -> r) -> Format r (Double -> r)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Builder -> Format (Double -> r) (Double -> r)
forall r. Builder -> Format r r
now Builder
x Format (Double -> r) (Double -> r)
-> Format r (Double -> r) -> Format r (Double -> r)
forall r a r'. Format r a -> Format r' r -> Format r' a
% Format r (Double -> r)
forall r. Format r (Double -> r)
double

-- | Optional number. Example: G01 does not require a Z position, hence @optional "Z"@.
optional :: TL.Builder -> Format r (Maybe Double -> r)
optional :: forall r. Builder -> Format r (Maybe Double -> r)
optional = Format Builder (Double -> Builder) -> Format r (Maybe Double -> r)
forall a r.
Format Builder (a -> Builder) -> Format r (Maybe a -> r)
optioned (Format Builder (Double -> Builder)
 -> Format r (Maybe Double -> r))
-> (Builder -> Format Builder (Double -> Builder))
-> Builder
-> Format r (Maybe Double -> r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Format Builder (Double -> Builder)
forall r. Builder -> Format r (Double -> r)
required

double :: Format r (Double -> r)
double :: forall r. Format r (Double -> r)
double = let decimals :: Int
decimals = Int
3 in Int -> Format r (Double -> r)
forall a r. Real a => Int -> Format r (a -> r)
fixed Int
decimals