Noah Vogt 2 місяців тому
батько
коміт
795f4850bd
2 змінених файлів з 62 додано та 29 видалено
  1. 30 22
      VulcanBoard.py
  2. 32 7
      config/load.py

+ 30 - 22
VulcanBoard.py

@@ -144,29 +144,37 @@ class VulcanBoardApp(App):
     async def execute_command_async(
         self, states: list, state_id: list[int], btn: AutoResizeButton
     ):
-        new_state_id = get_state_id_from_exit_code(states, state_id[0])
-        try:
-            print(states[new_state_id]["cmd"])
-            process = await asyncio.create_subprocess_shell(
-                get_state_from_id(states, new_state_id)["cmd"], shell=True
-            )
-            exit_code = await process.wait()
-            print(f"EXIT {exit_code}")
-            log(
-                f"Executed command: {get_state_from_id(states, new_state_id)['cmd']}"
-            )
-        except Exception as e:
-            exit_code = ERROR_SINK_STATE_ID
-            log(f"Error executing command: {e}", color="yellow")
-
-        if len(states) != 1:
-            state_id[0] = exit_code  # pyright: ignore
-
-            Clock.schedule_once(
-                lambda _: self.update_button_feedback(
-                    states, btn, exit_code  # pyright: ignore
+        follow_up_state_loop = True
+        while follow_up_state_loop:
+            new_state_id = get_state_id_from_exit_code(states, state_id[0])
+            state = get_state_from_id(states, new_state_id)
+            follow_up_state_loop = False
+
+            try:
+                print(states[new_state_id]["cmd"])
+                process = await asyncio.create_subprocess_shell(
+                    state["cmd"], shell=True
+                )
+                exit_code = await process.wait()
+                print(f"EXIT {exit_code}")
+                log(f"Executed command: {state['cmd']}")
+            except Exception as e:
+                exit_code = ERROR_SINK_STATE_ID
+                log(f"Error executing command: {e}", color="yellow")
+
+            if len(states) != 1:
+                if isinstance(
+                    follow_up_state := state.get("follow_up_state"), int
+                ):
+                    follow_up_state_loop = True
+                    exit_code = follow_up_state
+                state_id[0] = exit_code  # pyright: ignore
+
+                Clock.schedule_once(
+                    lambda _: self.update_button_feedback(
+                        states, btn, exit_code  # pyright: ignore
+                    )
                 )
-            )
 
     def update_button_feedback(
         self, states: list, btn: AutoResizeButton, exit_code: int

+ 32 - 7
config/load.py

@@ -110,24 +110,31 @@ class ConfigLoader:
                 )
 
             defined_state_ids = set()
+            to_follow_up_state_ids = set()
             for state in states:
                 if not (
                     isinstance(state, dict)
-                    or isinstance(state.get("id", None), int)
-                    or isinstance(state.get("cmd", None), str)
-                    or isinstance(state.get("txt", None), str)
+                    and isinstance(state_id := state.get("id", None), int)
                 ):
                     raise CustomException(
-                        f"invalid {btn_dims}: invalid state detected"
+                        f"invalid {btn_dims}: invalid state id detected"
                     )
                 state_id = state.get("id", None)
                 if isinstance(state_id, int):
                     if state_id in defined_state_ids:
                         raise CustomException(
-                            f"invalid {btn_dims}: tried to define state {state_id} twice"
+                            f"invalid {btn_dims}: tried to define state "
+                            + f"'{state_id}' twice"
                         )
                     defined_state_ids.add(state_id)
 
+                for string in ("cmd", "txt"):
+                    if not isinstance(state.get(string, ""), str):
+                        raise CustomException(
+                            f"invalid {btn_dims}: invalid '{string}' subentry "
+                            + f"for state id '{state_id}': must be a string"
+                        )
+
                 for color_pair in ("bg_color", DEFAULT_BUTTON_BG_COLOR), (
                     "fg_color",
                     DEFAULT_BUTTON_FG_COLOR,
@@ -137,14 +144,32 @@ class ConfigLoader:
                         str,
                     ) or not is_valid_hexcolor(color):
                         raise CustomException(
-                            f"invalid {btn_dims} '{color_pair[0]}' subentry: '{color}'"
+                            f"invalid {btn_dims}: '{color_pair[0]}' subentry "
+                            + f"for state '{state_id}': '{color}'"
                         )
 
+                follow_up_state = state.get("follow_up_state", 0)
+                if not isinstance(follow_up_state, int):
+                    raise CustomException(
+                        f"invalid {btn_dims}: 'follow_up_state' subentry for"
+                        + f" state '{state_id}': must be int"
+                    )
+                to_follow_up_state_ids.add(follow_up_state)
+
             if not DEFAULT_STATE_ID in defined_state_ids:
                 raise CustomException(
-                    f"invalid {btn_dims}: missing default state id '{DEFAULT_STATE_ID}'"
+                    f"invalid {btn_dims}: missing default state id "
+                    + f"'{DEFAULT_STATE_ID}'"
                 )
 
+            for follow_up_state_id in to_follow_up_state_ids:
+                if follow_up_state_id not in defined_state_ids:
+                    raise CustomException(
+                        f"invalid {btn_dims}: invalid 'follow_up_state' "
+                        + f"subentry found: state '{follow_up_state_id}' does "
+                        + "not exist"
+                    )
+
     def __validate_dimensions(self) -> None:
         for dimension in (self.columns, self.rows):
             if not isinstance(dimension, int) or (dimension <= 0):