particle: on-click: tilde expansion

We now do tilde expansion of the *first* argument in on-click
handlers.

That is:

  ~/bin/foobar.sh ~/arg1

is expanded to

  $HOME/bin/foobar.sh ~/arg1

(meaning, the handler will most likely *not* do what you’d expect)

Related to #307
This commit is contained in:
Daniel Eklöf 2023-07-11 10:26:28 +02:00
parent f948b9f8f9
commit d6e7710a7e
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 77 additions and 21 deletions

View file

@ -19,10 +19,12 @@
* i3/sway: extend option `sort`; use `native` to sort numbered workspaces only. * i3/sway: extend option `sort`; use `native` to sort numbered workspaces only.
* modules/dwl: handle the appid status ([#284][284]) * modules/dwl: handle the appid status ([#284][284])
* battery: also show estimation for time to full ([#303][303]). * battery: also show estimation for time to full ([#303][303]).
* on-click: tilde expansion ([#307][307])
[246]: https://codeberg.org/dnkl/yambar/issues/246 [246]: https://codeberg.org/dnkl/yambar/issues/246
[256]: https://codeberg.org/dnkl/yambar/pulls/256 [256]: https://codeberg.org/dnkl/yambar/pulls/256
[284]: https://codeberg.org/dnkl/yambar/pulls/284 [284]: https://codeberg.org/dnkl/yambar/pulls/284
[307]: https://codeberg.org/dnkl/yambar/issues/307
### Changed ### Changed

View file

@ -174,22 +174,47 @@ conf_verify_dict(keychain_t *chain, const struct yml_node *node,
return true; return true;
} }
static bool
verify_on_click_path(keychain_t *chain, const struct yml_node *node)
{
if (!conf_verify_string(chain, node))
return false;
#if 1
/* We allow non-absolute paths in on-click handlers */
return true;
#else
const char *path = yml_value_as_string(node);
const bool is_absolute = path[0] == '/';
const bool is_tilde = path[0] == '~' && path[1] == '/';
if (!is_absolute && !is_tilde) {
LOG_ERR("%s: path must be either absolute, or begin with '~/",
conf_err_prefix(chain, node));
return false;
}
return true;
#endif
}
bool bool
conf_verify_on_click(keychain_t *chain, const struct yml_node *node) conf_verify_on_click(keychain_t *chain, const struct yml_node *node)
{ {
/* on-click: <command> */ /* on-click: <command> */
const char *s = yml_value_as_string(node); const char *s = yml_value_as_string(node);
if (s != NULL) if (s != NULL)
return true; return verify_on_click_path(chain, node);
static const struct attr_info info[] = { static const struct attr_info info[] = {
{"left", false, &conf_verify_string}, {"left", false, &verify_on_click_path},
{"middle", false, &conf_verify_string}, {"middle", false, &verify_on_click_path},
{"right", false, &conf_verify_string}, {"right", false, &verify_on_click_path},
{"wheel-up", false, &conf_verify_string}, {"wheel-up", false, &verify_on_click_path},
{"wheel-down", false, &conf_verify_string}, {"wheel-down", false, &verify_on_click_path},
{"previous", false, &conf_verify_string}, {"previous", false, &verify_on_click_path},
{"next", false, &conf_verify_string}, {"next", false, &verify_on_click_path},
{NULL, false, NULL}, {NULL, false, NULL},
}; };
@ -306,7 +331,8 @@ conf_verify_particle_dictionary(keychain_t *chain, const struct yml_node *node)
const char *particle_name = yml_value_as_string(particle); const char *particle_name = yml_value_as_string(particle);
if (particle_name == NULL) { if (particle_name == NULL) {
LOG_ERR("%s: particle name must be a string", conf_err_prefix(chain, particle)); LOG_ERR("%s: particle name must be a string",
conf_err_prefix(chain, particle));
return false; return false;
} }

View file

@ -211,20 +211,47 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited)
int right = margin != NULL ? yml_value_as_int(margin) : int right = margin != NULL ? yml_value_as_int(margin) :
right_margin != NULL ? yml_value_as_int(right_margin) : 0; right_margin != NULL ? yml_value_as_int(right_margin) : 0;
const char *on_click_templates[MOUSE_BTN_COUNT] = {NULL}; char *on_click_templates[MOUSE_BTN_COUNT] = {NULL};
if (on_click != NULL) { if (on_click != NULL) {
const char *legacy = yml_value_as_string(on_click); const char *yml_legacy = yml_value_as_string(on_click);
if (yml_legacy != NULL) {
char *legacy = NULL;
if (yml_legacy[0] == '~' && yml_legacy[1] == '/') {
const char *home_dir = getenv("HOME");
if (home_dir != NULL)
asprintf(&legacy, "%s/%s", home_dir, yml_legacy + 2);
if (legacy == NULL)
legacy = strdup(yml_legacy);
} else
legacy = strdup(yml_legacy);
if (legacy != NULL)
on_click_templates[MOUSE_BTN_LEFT] = legacy; on_click_templates[MOUSE_BTN_LEFT] = legacy;
}
if (yml_is_dict(on_click)) { else if (yml_is_dict(on_click)) {
for (struct yml_dict_iter it = yml_dict_iter(on_click); for (struct yml_dict_iter it = yml_dict_iter(on_click);
it.key != NULL; it.key != NULL;
yml_dict_next(&it)) yml_dict_next(&it))
{ {
const char *key = yml_value_as_string(it.key); const char *key = yml_value_as_string(it.key);
const char *template = yml_value_as_string(it.value); const char *yml_template = yml_value_as_string(it.value);
char *template = NULL;
if (yml_template[0] == '~' && yml_template[1] == '/') {
const char *home_dir = getenv("HOME");
if (home_dir != NULL)
asprintf(&template, "%s/%s", home_dir, yml_template + 2);
if (template == NULL)
template = strdup(yml_template);
} else
template = strdup(yml_template);
if (strcmp(key, "left") == 0) if (strcmp(key, "left") == 0)
on_click_templates[MOUSE_BTN_LEFT] = template; on_click_templates[MOUSE_BTN_LEFT] = template;

View file

@ -44,10 +44,11 @@ following attributes are supported by all particles:
| on-click | on-click
: associative array/string : associative array/string
: no : no
: When set to a string, executes the string as a command when the particle : When set to a string, executes the string as a command when the
is left-clicked. Tags can be used. Note that the string is *not* particle is left-clicked. Tags can be used. Note that the string is
executed in a shell. The same applies to all attributes associated with *not* executed in a shell. Environment variables are not expanded.
it, below. *~/* is expanded, but only in the first argument. The same applies
to all attributes associated with it, below.
| on-click.left | on-click.left
: string : string
: no : no

View file

@ -30,7 +30,7 @@ particle_default_destroy(struct particle *particle)
struct particle * struct particle *
particle_common_new(int left_margin, int right_margin, particle_common_new(int left_margin, int right_margin,
const char **on_click_templates, char **on_click_templates,
struct fcft_font *font, enum font_shaping font_shaping, struct fcft_font *font, enum font_shaping font_shaping,
pixman_color_t foreground, struct deco *deco) pixman_color_t foreground, struct deco *deco)
{ {
@ -46,7 +46,7 @@ particle_common_new(int left_margin, int right_margin,
for (size_t i = 0; i < MOUSE_BTN_COUNT; i++) { for (size_t i = 0; i < MOUSE_BTN_COUNT; i++) {
if (on_click_templates[i] != NULL) { if (on_click_templates[i] != NULL) {
p->have_on_click_template = true; p->have_on_click_template = true;
p->on_click_templates[i] = strdup(on_click_templates[i]); p->on_click_templates[i] = on_click_templates[i];
} }
} }
} }

View file

@ -64,7 +64,7 @@ struct exposable {
}; };
struct particle *particle_common_new( struct particle *particle_common_new(
int left_margin, int right_margin, const char *on_click_templates[], int left_margin, int right_margin, char *on_click_templates[],
struct fcft_font *font, enum font_shaping font_shaping, struct fcft_font *font, enum font_shaping font_shaping,
pixman_color_t foreground, struct deco *deco); pixman_color_t foreground, struct deco *deco);