]> git.mdlowis.com Git - proto/labwc.git/commitdiff
rcxml: rewrite action parser
authortokyo4j <hrak1529@gmail.com>
Fri, 11 Apr 2025 15:57:03 +0000 (00:57 +0900)
committerJohan Malm <johanmalm@users.noreply.github.com>
Wed, 30 Jul 2025 19:36:27 +0000 (20:36 +0100)
This commit rewrites the nested action parser into append_actions() which
is used by following commits. At this point, it's not used yet and parsing
"If" action is temporarily disabled.

src/config/rcxml.c

index c3abbf930eb066a0245043f6f99a7fce3cb03c01..bf108cae158ed21077c9cd17919e153f6223403e 100644 (file)
@@ -432,112 +432,141 @@ fill_region(char *nodename, char *content, struct parser_state *state)
 }
 
 static void
-fill_action_query(char *nodename, char *content, struct action *action, struct parser_state *state)
+fill_action_query(struct action *action, xmlNode *node, struct view_query *query)
 {
-       if (!action) {
-               wlr_log(WLR_ERROR, "No parent action for query: %s=%s", nodename, content);
-               return;
-       }
-
-       string_truncate_at_pattern(nodename, ".keybind.keyboard");
-       string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
-
-       if (!strcasecmp(nodename, "query.action")) {
-               state->current_view_query = NULL;
-       }
-
-       string_truncate_at_pattern(nodename, ".query.action");
-
-       if (!content) {
-               return;
-       }
-
-       if (!state->current_view_query) {
-               struct wl_list *queries = action_get_querylist(action, "query");
-               if (!queries) {
-                       action_arg_add_querylist(action, "query");
-                       queries = action_get_querylist(action, "query");
+       xmlNode *child;
+       char *key, *content;
+       LAB_XML_FOR_EACH(node, child, key, content) {
+               if (!strcasecmp(key, "identifier")) {
+                       xstrdup_replace(query->identifier, content);
+               } else if (!strcasecmp(key, "title")) {
+                       xstrdup_replace(query->title, content);
+               } else if (!strcmp(key, "type")) {
+                       query->window_type = parse_window_type(content);
+               } else if (!strcasecmp(key, "sandboxEngine")) {
+                       xstrdup_replace(query->sandbox_engine, content);
+               } else if (!strcasecmp(key, "sandboxAppId")) {
+                       xstrdup_replace(query->sandbox_app_id, content);
+               } else if (!strcasecmp(key, "shaded")) {
+                       query->shaded = parse_three_state(content);
+               } else if (!strcasecmp(key, "maximized")) {
+                       query->maximized = view_axis_parse(content);
+               } else if (!strcasecmp(key, "iconified")) {
+                       query->iconified = parse_three_state(content);
+               } else if (!strcasecmp(key, "focused")) {
+                       query->focused = parse_three_state(content);
+               } else if (!strcasecmp(key, "omnipresent")) {
+                       query->omnipresent = parse_three_state(content);
+               } else if (!strcasecmp(key, "tiled")) {
+                       query->tiled = view_edge_parse(content);
+               } else if (!strcasecmp(key, "tiled_region")) {
+                       xstrdup_replace(query->tiled_region, content);
+               } else if (!strcasecmp(key, "desktop")) {
+                       xstrdup_replace(query->desktop, content);
+               } else if (!strcasecmp(key, "decoration")) {
+                       query->decoration = ssd_mode_parse(content);
+               } else if (!strcasecmp(key, "monitor")) {
+                       xstrdup_replace(query->monitor, content);
                }
-               state->current_view_query = view_query_create();
-               wl_list_append(queries, &state->current_view_query->link);
-       }
-
-       if (!strcasecmp(nodename, "identifier")) {
-               xstrdup_replace(state->current_view_query->identifier, content);
-       } else if (!strcasecmp(nodename, "title")) {
-               xstrdup_replace(state->current_view_query->title, content);
-       } else if (!strcmp(nodename, "type")) {
-               state->current_view_query->window_type = parse_window_type(content);
-       } else if (!strcasecmp(nodename, "sandboxEngine")) {
-               xstrdup_replace(state->current_view_query->sandbox_engine, content);
-       } else if (!strcasecmp(nodename, "sandboxAppId")) {
-               xstrdup_replace(state->current_view_query->sandbox_app_id, content);
-       } else if (!strcasecmp(nodename, "shaded")) {
-               state->current_view_query->shaded = parse_three_state(content);
-       } else if (!strcasecmp(nodename, "maximized")) {
-               state->current_view_query->maximized = view_axis_parse(content);
-       } else if (!strcasecmp(nodename, "iconified")) {
-               state->current_view_query->iconified = parse_three_state(content);
-       } else if (!strcasecmp(nodename, "focused")) {
-               state->current_view_query->focused = parse_three_state(content);
-       } else if (!strcasecmp(nodename, "omnipresent")) {
-               state->current_view_query->omnipresent = parse_three_state(content);
-       } else if (!strcasecmp(nodename, "tiled")) {
-               state->current_view_query->tiled = view_edge_parse(content);
-       } else if (!strcasecmp(nodename, "tiled_region")) {
-               xstrdup_replace(state->current_view_query->tiled_region, content);
-       } else if (!strcasecmp(nodename, "desktop")) {
-               xstrdup_replace(state->current_view_query->desktop, content);
-       } else if (!strcasecmp(nodename, "decoration")) {
-               state->current_view_query->decoration = ssd_mode_parse(content);
-       } else if (!strcasecmp(nodename, "monitor")) {
-               xstrdup_replace(state->current_view_query->monitor, content);
        }
 }
 
+static void append_actions(xmlNode *node, struct wl_list *list);
+
 static void
-fill_child_action(char *nodename, char *content, struct action *parent,
-       const char *branch_name, struct parser_state *state)
+parse_action_args(xmlNode *node, struct action *action)
 {
-       if (!parent) {
-               wlr_log(WLR_ERROR, "No parent action for branch: %s=%s", nodename, content);
-               return;
+       xmlNode *child;
+       char *key, *content;
+       LAB_XML_FOR_EACH(node, child, key, content) {
+               if (!strcasecmp(key, "query")) {
+                       struct wl_list *querylist =
+                               action_get_querylist(action, "query");
+                       if (!querylist) {
+                               action_arg_add_querylist(action, "query");
+                               querylist = action_get_querylist(action, "query");
+                       }
+                       struct view_query *query = view_query_create();
+                       fill_action_query(action, child, query);
+                       wl_list_append(querylist, &query->link);
+               } else if (!strcasecmp(key, "then")) {
+                       struct wl_list *actions =
+                               action_get_actionlist(action, "then");
+                       if (!actions) {
+                               action_arg_add_actionlist(action, "then");
+                               actions = action_get_actionlist(action, "then");
+                       }
+                       append_actions(child, actions);
+               } else if (!strcasecmp(key, "else")) {
+                       struct wl_list *actions =
+                               action_get_actionlist(action, "else");
+                       if (!actions) {
+                               action_arg_add_actionlist(action, "else");
+                               actions = action_get_actionlist(action, "else");
+                       }
+                       append_actions(child, actions);
+               } else if (!strcasecmp(key, "none")) {
+                       struct wl_list *actions =
+                               action_get_actionlist(action, "none");
+                       if (!actions) {
+                               action_arg_add_actionlist(action, "none");
+                               actions = action_get_actionlist(action, "none");
+                       }
+                       append_actions(child, actions);
+               } else if (!strcasecmp(key, "name")) {
+                       /* Ignore <action name=""> */
+               } else if (lab_xml_node_is_leaf(child)) {
+                       /* Handle normal action args */
+                       char buffer[256];
+                       char *node_name = nodename(child, buffer, sizeof(buffer));
+                       action_arg_from_xml_node(action, node_name, content);
+               } else {
+                       /* Handle nested args like <position><x> in ShowMenu */
+                       parse_action_args(child, action);
+               }
        }
+}
 
-       string_truncate_at_pattern(nodename, ".keybind.keyboard");
-       string_truncate_at_pattern(nodename, ".mousebind.context.mouse");
-       string_truncate_at_pattern(nodename, ".then.action");
-       string_truncate_at_pattern(nodename, ".else.action");
-       string_truncate_at_pattern(nodename, ".none.action");
+static struct action *
+parse_action(xmlNode *node)
+{
+       char name[256];
+       struct action *action = NULL;
 
-       if (!strcasecmp(nodename, "action")) {
-               state->current_child_action = NULL;
+       if (lab_xml_get_string(node, "name", name, sizeof(name))) {
+               action = action_create(name);
        }
-
-       if (!content) {
-               return;
+       if (!action) {
+               return NULL;
        }
 
-       struct wl_list *siblings = action_get_actionlist(parent, branch_name);
-       if (!siblings) {
-               action_arg_add_actionlist(parent, branch_name);
-               siblings = action_get_actionlist(parent, branch_name);
-       }
+       parse_action_args(node, action);
+       return action;
+}
 
-       if (!strcasecmp(nodename, "name.action")) {
-               if (!strcasecmp(content, "If") || !strcasecmp(content, "ForEach")) {
-                       wlr_log(WLR_ERROR, "action '%s' cannot be a child action", content);
-                       return;
+static void
+append_actions(xmlNode *node, struct wl_list *list)
+{
+       xmlNode *child;
+       char *key, *content;
+       LAB_XML_FOR_EACH(node, child, key, content) {
+               if (strcasecmp(key, "action")) {
+                       continue;
                }
-               state->current_child_action = action_create(content);
-               if (state->current_child_action) {
-                       wl_list_append(siblings, &state->current_child_action->link);
+               if (lab_xml_node_is_leaf(child)) {
+                       /*
+                        * A mousebind contains two types of "action" nodes:
+                        *   <mousebind button="Left" action="Click">
+                        *     <action name="Close" />
+                        *   </mousebind>
+                        * The first node (action="Click") is skipped.
+                        */
+                       continue;
+               }
+               struct action *action = parse_action(child);
+               if (action) {
+                       wl_list_append(list, &action->link);
                }
-       } else if (!state->current_child_action) {
-               wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
-                       "nodename: '%s' content: '%s'", nodename, content);
-       } else {
-               action_arg_from_xml_node(state->current_child_action, nodename, content);
        }
 }
 
@@ -1055,38 +1084,10 @@ entry(xmlNode *node, char *nodename, char *content, struct parser_state *state)
                fill_usable_area_override(nodename, content, state);
        }
        if (state->in_keybind) {
-               if (state->in_action_query) {
-                       fill_action_query(nodename, content,
-                               state->current_keybind_action, state);
-               } else if (state->in_action_then_branch) {
-                       fill_child_action(nodename, content,
-                               state->current_keybind_action, "then", state);
-               } else if (state->in_action_else_branch) {
-                       fill_child_action(nodename, content,
-                               state->current_keybind_action, "else", state);
-               } else if (state->in_action_none_branch) {
-                       fill_child_action(nodename, content,
-                               state->current_keybind_action, "none", state);
-               } else {
-                       fill_keybind(nodename, content, state);
-               }
+               fill_keybind(nodename, content, state);
        }
        if (state->in_mousebind) {
-               if (state->in_action_query) {
-                       fill_action_query(nodename, content,
-                               state->current_mousebind_action, state);
-               } else if (state->in_action_then_branch) {
-                       fill_child_action(nodename, content,
-                               state->current_mousebind_action, "then", state);
-               } else if (state->in_action_else_branch) {
-                       fill_child_action(nodename, content,
-                               state->current_mousebind_action, "else", state);
-               } else if (state->in_action_none_branch) {
-                       fill_child_action(nodename, content,
-                               state->current_mousebind_action, "none", state);
-               } else {
-                       fill_mousebind(nodename, content, state);
-               }
+               fill_mousebind(nodename, content, state);
        }
        if (state->in_touch) {
                fill_touch(nodename, content, state);