How to Code Macros (PROS)

That first way of doing button macros is very similar to a statemachine. However, some syntactic improvements can be made.
It is a good idea to enumerate your states using enum or enum class and it is better to use a switch statement instead of an if/elseif/else tree.
Here is an example:

enum class liftStates {
  off,
  up,
  waitForPress
};

liftStates liftState = liftStates::off;

while(true) {
  switch(liftState) {
    case liftStates::off:
    lift.move(0);
    break;

    case liftStates::up:
    lift.move(127);
    break;

    case liftStates::waitForPress:
    if(button press) liftState = liftStates::up;
    break;
  }
  pros::delay(20);
}

You can see this leads to a cleaner and more concise code.

In my code last year, I ended up using a massive statemachine for my flywheel angler, that used a queue to load up a series of commands that would execute in a sequence, and insert new states if needed.

  enum shootStates {
    off, //control to flywheel and intake
    standby, //back position, control to flywheel
    angling, //indefinite angling
    cycle, //head to back position
    extend, //move to extended position
    waitForSlip, //wait until hood slips
    waitForRetract, //wait until hood back to 0 pos
    angleTop, //drop hood to top angle
    angleMiddle, //drop hood to middle angle
    angleTopPlatform, //angle top from platform
    angleMiddlePlatform, //angle middle from platform
    angleOut, //drop hood to out (ground flag) angle
    angleTarget, //drop hood to target angle
    waitForDoubleShot, //if distance is large enough, wait before second shot
    waitForBall, //wait for ball to be in indexer
    waitForFlywheel, //wait until flywheel is ready
    enableShoot, //shoot indexer
    waitForShoot, //delay
    reportDone, //lets autonomous know sequence is done
    loopJob, //reloads current job
    loopMacro //reloads current macro
  };

I could then construct named macros with sequences of those actions, and have the macros trigger on button presses. For example, the doubleshot macro was done using this sequence: angleTop, enableShoot, angleMiddle, waitForDoubleShot, enableShoot, reportDone and the cycling would be automatically inserted in that sequence when needed.

I recommend everyone reads about statemachines, as they can be simply implemented (switch statements) and are very powerful.