opt: allow use comma symbol in spawn shell value

This commit is contained in:
DreamMaoMao 2026-02-03 10:06:26 +08:00
parent eb0607501d
commit 0546a2d4c4

View file

@ -550,6 +550,48 @@ static bool starts_with_ignore_case(const char *str, const char *prefix) {
return true; return true;
} }
static char *combine_args_until_empty(char *values[], int count) {
// find the first empty string
int first_empty = count;
for (int i = 0; i < count; i++) {
// check if it's empty: empty string or only contains "0" (initialized)
if (values[i][0] == '\0' ||
(strlen(values[i]) == 1 && values[i][0] == '0')) {
first_empty = i;
break;
}
}
// if there are no valid parameters, return an empty string
if (first_empty == 0) {
return strdup("");
}
// calculate the total length
size_t total_len = 0;
for (int i = 0; i < first_empty; i++) {
total_len += strlen(values[i]);
}
// plus the number of commas (first_empty-1 commas)
total_len += (first_empty - 1);
// allocate memory and concatenate
char *combined = malloc(total_len + 1);
if (combined == NULL) {
return strdup("");
}
combined[0] = '\0';
for (int i = 0; i < first_empty; i++) {
if (i > 0) {
strcat(combined, ",");
}
strcat(combined, values[i]);
}
return combined;
}
uint32_t parse_mod(const char *mod_str) { uint32_t parse_mod(const char *mod_str) {
if (!mod_str || !*mod_str) { if (!mod_str || !*mod_str) {
return UINT32_MAX; return UINT32_MAX;
@ -1005,10 +1047,14 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
(*arg).ui = atoi(arg_value); (*arg).ui = atoi(arg_value);
} else if (strcmp(func_name, "spawn") == 0) { } else if (strcmp(func_name, "spawn") == 0) {
func = spawn; func = spawn;
(*arg).v = strdup(arg_value); char *values[] = {arg_value, arg_value2, arg_value3, arg_value4,
arg_value5};
(*arg).v = combine_args_until_empty(values, 5);
} else if (strcmp(func_name, "spawn_shell") == 0) { } else if (strcmp(func_name, "spawn_shell") == 0) {
func = spawn_shell; func = spawn_shell;
(*arg).v = strdup(arg_value); char *values[] = {arg_value, arg_value2, arg_value3, arg_value4,
arg_value5};
(*arg).v = combine_args_until_empty(values, 5);
} else if (strcmp(func_name, "spawn_on_empty") == 0) { } else if (strcmp(func_name, "spawn_on_empty") == 0) {
func = spawn_on_empty; func = spawn_on_empty;
(*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存 (*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存
@ -1385,9 +1431,8 @@ bool parse_option(Config *config, char *key, char *value) {
config->scroller_proportion_preset = config->scroller_proportion_preset =
(float *)malloc(float_count * sizeof(float)); (float *)malloc(float_count * sizeof(float));
if (!config->scroller_proportion_preset) { if (!config->scroller_proportion_preset) {
fprintf( fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory "
stderr, "allocation failed\n");
"\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n");
return false; return false;
} }
@ -1400,18 +1445,19 @@ bool parse_option(Config *config, char *key, char *value) {
while (token != NULL && i < float_count) { while (token != NULL && i < float_count) {
if (sscanf(token, "%f", &value_set) != 1) { if (sscanf(token, "%f", &value_set) != 1) {
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid float "
"\033[1m\033[31m[ERROR]:\033[33m Invalid float value in " "value in "
"scroller_proportion_preset: %s\n", "scroller_proportion_preset: %s\n",
token); token);
free(value_copy); free(value_copy);
free(config->scroller_proportion_preset); free(config->scroller_proportion_preset);
config->scroller_proportion_preset = NULL; config->scroller_proportion_preset = NULL;
return false; return false;
} }
// Clamp the value between 0.0 and 1.0 (or your desired range) // Clamp the value between 0.0 and 1.0 (or your desired
// range)
config->scroller_proportion_preset[i] = config->scroller_proportion_preset[i] =
CLAMP_FLOAT(value_set, 0.1f, 1.0f); CLAMP_FLOAT(value_set, 0.1f, 1.0f);
@ -1448,9 +1494,8 @@ bool parse_option(Config *config, char *key, char *value) {
config->circle_layout = (char **)malloc(string_count * sizeof(char *)); config->circle_layout = (char **)malloc(string_count * sizeof(char *));
memset(config->circle_layout, 0, string_count * sizeof(char *)); memset(config->circle_layout, 0, string_count * sizeof(char *));
if (!config->circle_layout) { if (!config->circle_layout) {
fprintf( fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory "
stderr, "allocation failed\n");
"\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n");
return false; return false;
} }
@ -1606,7 +1651,8 @@ bool parse_option(Config *config, char *key, char *value) {
int64_t color = parse_color(value); int64_t color = parse_color(value);
if (color == -1) { if (color == -1) {
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor format: " "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor "
"format: "
"%s\n", "%s\n",
value); value);
return false; return false;
@ -1650,11 +1696,11 @@ bool parse_option(Config *config, char *key, char *value) {
} else if (strcmp(key, "maximizescreencolor") == 0) { } else if (strcmp(key, "maximizescreencolor") == 0) {
int64_t color = parse_color(value); int64_t color = parse_color(value);
if (color == -1) { if (color == -1) {
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid "
"\033[1m\033[31m[ERROR]:\033[33m Invalid maximizescreencolor " "maximizescreencolor "
"format: %s\n", "format: %s\n",
value); value);
return false; return false;
} else { } else {
convert_hex_to_rgba(config->maximizescreencolor, color); convert_hex_to_rgba(config->maximizescreencolor, color);
@ -1674,7 +1720,8 @@ bool parse_option(Config *config, char *key, char *value) {
int64_t color = parse_color(value); int64_t color = parse_color(value);
if (color == -1) { if (color == -1) {
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid scratchpadcolor " "\033[1m\033[31m[ERROR]:\033[33m Invalid "
"scratchpadcolor "
"format: %s\n", "format: %s\n",
value); value);
return false; return false;
@ -1760,11 +1807,11 @@ bool parse_option(Config *config, char *key, char *value) {
} else if (strcmp(key, "vrr") == 0) { } else if (strcmp(key, "vrr") == 0) {
rule->vrr = CLAMP_INT(atoi(val), 0, 1); rule->vrr = CLAMP_INT(atoi(val), 0, 1);
} else { } else {
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"\033[1m\033[31m[ERROR]:\033[33m Unknown monitor rule " "monitor rule "
"option:\033[1m\033[31m %s\n", "option:\033[1m\033[31m %s\n",
key); key);
parse_error = true; parse_error = true;
} }
} }
@ -1824,7 +1871,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f);
} else { } else {
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown tag rule " "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"tag rule "
"option:\033[1m\033[31m %s\n", "option:\033[1m\033[31m %s\n",
key); key);
parse_error = true; parse_error = true;
@ -1882,11 +1930,11 @@ bool parse_option(Config *config, char *key, char *value) {
} else if (strcmp(key, "noshadow") == 0) { } else if (strcmp(key, "noshadow") == 0) {
rule->noshadow = CLAMP_INT(atoi(val), 0, 1); rule->noshadow = CLAMP_INT(atoi(val), 0, 1);
} else { } else {
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"\033[1m\033[31m[ERROR]:\033[33m Unknown layer rule " "layer rule "
"option:\033[1m\033[31m %s\n", "option:\033[1m\033[31m %s\n",
key); key);
parse_error = true; parse_error = true;
} }
} }
@ -2074,11 +2122,11 @@ bool parse_option(Config *config, char *key, char *value) {
return false; return false;
} }
} else { } else {
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"\033[1m\033[31m[ERROR]:\033[33m Unknown window rule " "window rule "
"option:\033[1m\033[31m %s\n", "option:\033[1m\033[31m %s\n",
key); key);
parse_error = true; parse_error = true;
} }
} }
@ -2178,7 +2226,8 @@ bool parse_option(Config *config, char *key, char *value) {
arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0"; arg_value5[256] = "0\0";
if (sscanf(value, if (sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^"
",],%255["
"^,],%255[^\n]", "^,],%255[^\n]",
mod_str, keysym_str, func_name, arg_value, arg_value2, mod_str, keysym_str, func_name, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5) < 3) { arg_value3, arg_value4, arg_value5) < 3) {
@ -2235,11 +2284,11 @@ bool parse_option(Config *config, char *key, char *value) {
binding->arg.v3 = NULL; binding->arg.v3 = NULL;
} }
if (!binding->func) if (!binding->func)
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in bind: " "dispatch in bind: "
"\033[1m\033[31m%s\n", "\033[1m\033[31m%s\n",
func_name); func_name);
return false; return false;
} else { } else {
config->key_bindings_count++; config->key_bindings_count++;
@ -2265,12 +2314,14 @@ bool parse_option(Config *config, char *key, char *value) {
arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0"; arg_value5[256] = "0\0";
if (sscanf(value, if (sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^"
",],%255["
"^,],%255[^\n]", "^,],%255[^\n]",
mod_str, button_str, func_name, arg_value, arg_value2, mod_str, button_str, func_name, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5) < 3) { arg_value3, arg_value4, arg_value5) < 3) {
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind format: " "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind "
"format: "
"%s\n", "%s\n",
value); value);
return false; return false;
@ -2308,7 +2359,8 @@ bool parse_option(Config *config, char *key, char *value) {
} }
if (!binding->func) if (!binding->func)
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"dispatch in "
"mousebind: \033[1m\033[31m%s\n", "mousebind: \033[1m\033[31m%s\n",
func_name); func_name);
return false; return false;
@ -2335,14 +2387,15 @@ bool parse_option(Config *config, char *key, char *value) {
arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0"; arg_value5[256] = "0\0";
if (sscanf(value, if (sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^"
",],%255["
"^,],%255[^\n]", "^,],%255[^\n]",
mod_str, dir_str, func_name, arg_value, arg_value2, mod_str, dir_str, func_name, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5) < 3) { arg_value3, arg_value4, arg_value5) < 3) {
fprintf( fprintf(stderr,
stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind "
"\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind format: %s\n", "format: %s\n",
value); value);
return false; return false;
} }
@ -2379,7 +2432,8 @@ bool parse_option(Config *config, char *key, char *value) {
} }
if (!binding->func) if (!binding->func)
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"dispatch in "
"axisbind: \033[1m\033[31m%s\n", "axisbind: \033[1m\033[31m%s\n",
func_name); func_name);
return false; return false;
@ -2407,7 +2461,8 @@ bool parse_option(Config *config, char *key, char *value) {
arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0"; arg_value5[256] = "0\0";
if (sscanf(value, if (sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^"
",],%255["
"^\n]", "^\n]",
fold_str, func_name, arg_value, arg_value2, arg_value3, fold_str, func_name, arg_value, arg_value2, arg_value3,
arg_value4, arg_value5) < 3) { arg_value4, arg_value5) < 3) {
@ -2474,7 +2529,8 @@ bool parse_option(Config *config, char *key, char *value) {
arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "0\0"; arg_value5[256] = "0\0";
if (sscanf(value, if (sscanf(value,
"%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^"
",],%255["
"^,],%255[^,],%255[^\n]", "^,],%255[^,],%255[^\n]",
mod_str, motion_str, fingers_count_str, func_name, arg_value, mod_str, motion_str, fingers_count_str, func_name, arg_value,
arg_value2, arg_value3, arg_value4, arg_value5) < 4) { arg_value2, arg_value3, arg_value4, arg_value5) < 4) {
@ -2520,7 +2576,8 @@ bool parse_option(Config *config, char *key, char *value) {
} }
if (!binding->func) if (!binding->func)
fprintf(stderr, fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " "\033[1m\033[31m[ERROR]:\033[33m Unknown "
"dispatch in "
"axisbind: \033[1m\033[31m%s\n", "axisbind: \033[1m\033[31m%s\n",
func_name); func_name);
return false; return false;
@ -3134,8 +3191,8 @@ void set_value_default() {
config.hotarea_size = hotarea_size; // 热区大小,10x10 config.hotarea_size = hotarea_size; // 热区大小,10x10
config.hotarea_corner = hotarea_corner; config.hotarea_corner = hotarea_corner;
config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区 config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区
config.smartgaps = config.smartgaps = smartgaps; /* 1 means no outer gap when there is
smartgaps; /* 1 means no outer gap when there is only one window */ only one window */
config.sloppyfocus = sloppyfocus; /* focus follows mouse */ config.sloppyfocus = sloppyfocus; /* focus follows mouse */
config.gappih = gappih; /* horiz inner gap between windows */ config.gappih = gappih; /* horiz inner gap between windows */
config.gappiv = gappiv; /* vert inner gap between windows */ config.gappiv = gappiv; /* vert inner gap between windows */