~scoopta/wofi

1

[PATCH] Adding support for running commands on displayed entries

Details
Message ID
<CAGn0Psw1jF_AjkUVbFf8kjBknUQ_eN1Oukd4+rDYg_5rmYJA0A@mail.gmail.com>
DKIM signature
pass
Download raw message
I was annoyed that I didn't find a way to view the contents of the
files in my clipboard manager, listed through a pipe with dmenu mode,
yet still returning the original filenames. Created a patch which
solves it for my use case. By using `--pre-display-cmd` or `-r`, the
following string is used as a command to run on the visible string.
Use `%s` as a placeholder for the original string.

Example usage: `ls /some/path | wofi --show dmenu --pre-display-cmd
'cat /some/path/%s'`
%s is resolved as the different files in the path, thus reading the
contents of each file, which contents are displayed as selectable
entries. Output remains as the filename for the selected file.

Let me know if there's anything I should change.

```c
diff -r bae1c99a465f src/main.c
--- a/src/main.c Mon Feb 22 23:53:57 2021 -0800
+++ b/src/main.c Fri Oct 22 23:42:55 2021 +0200
@@ -96,6 +96,7 @@
  printf("--gtk-dark\t-G\tUses the dark variant of the current GTK theme\n");
  printf("--search\t-Q\tSearch for something immediately on open\n");
  printf("--monitor\t-o\tSets the monitor to open on\n");
+ printf("--pre-display-cmd\t-r\tRuns command for the displayed
entries, without changing the output. %%s for the real string\n");
  exit(0);
 }

@@ -106,7 +107,10 @@
  ssize_t size = ftell(file);
  fseek(file, 0, SEEK_SET);
  char* data = malloc(size + 1);
- fread(data, 1, size, file);
+ if (fread(data, 1, size, file) != 0) {
+ printf("failed to read stylesheet data from file");
+ exit(EXIT_FAILURE);
+ }
  fclose(file);

  data[size] = 0;
@@ -422,6 +426,12 @@
  .val = 'o'
  },
  {
+ .name = "pre-display-cmd",
+ .has_arg = required_argument,
+ .flag = NULL,
+ .val = 'r'
+ },
+ {
  .name = NULL,
  .has_arg = 0,
  .flag = NULL,
@@ -457,13 +467,14 @@
  char* gtk_dark = NULL;
  char* search = NULL;
  char* monitor = NULL;
+ char* pre_display_cmd = NULL;

  struct wl_list options;
  wl_list_init(&options);
  struct option_node* node;

  int opt;
- while((opt = getopt_long(argc, argv,
"hfc:s:C:dS:W:H:p:x:y:nImk:t:P::ebM:iqvl:aD:L:w:O:GQ:o:", opts, NULL))
!= -1) {
+ while((opt = getopt_long(argc, argv,
"hfc:s:C:dS:W:H:p:x:y:nImk:t:P::ebM:iqvl:aD:L:w:O:GQ:o:r:", opts,
NULL)) != -1) {
  switch(opt) {
  case 'h':
  print_usage(argv);
@@ -572,6 +583,9 @@
  case 'o':
  monitor = optarg;
  break;
+ case 'r':
+ pre_display_cmd = optarg;
+ break;
  }
  }

@@ -761,6 +775,9 @@
  if(monitor != NULL) {
  map_put(config, "monitor", monitor);
  }
+ if(pre_display_cmd != NULL) {
+ map_put(config, "pre_display_cmd", pre_display_cmd);
+ }

  struct sigaction sigact = {0};
  sigact.sa_handler = sig;
diff -r bae1c99a465f src/wofi.c
--- a/src/wofi.c Mon Feb 22 23:53:57 2021 -0800
+++ b/src/wofi.c Fri Oct 22 23:42:55 2021 +0200
@@ -106,6 +106,7 @@
 static pthread_t mode_thread;
 static bool has_joined_mode = false;
 static char* copy_exec = NULL;
+static char* pre_display_cmd = NULL;

 static struct map* keys;

@@ -396,10 +397,32 @@

  setup_label(mode, WOFI_PROPERTY_BOX(box));

+ char labeltext[1000];
+ if (pre_display_cmd == NULL) {
+ *labeltext = *text;
+ } else {
+ FILE *fp_labeltext;
+ char *cmd_labeltext;
+ if ((asprintf(&cmd_labeltext, pre_display_cmd, text)) == -1) {
+ printf("error parsing pre_display_cmd to run\n");
+ exit(EXIT_FAILURE);
+ }
+ fp_labeltext = popen(cmd_labeltext, "r");
+ if (fp_labeltext == NULL) {
+ printf("error executing '%s'", cmd_labeltext);
+ exit(EXIT_FAILURE);
+ }
+ if (fgets(labeltext, sizeof(labeltext), fp_labeltext) == NULL) {
+ printf("failed to read output of command");
+ exit(EXIT_FAILURE);
+ }
+ pclose(fp_labeltext);
+ }
+
  if(allow_images) {
- parse_images(WOFI_PROPERTY_BOX(box), text, true);
+ parse_images(WOFI_PROPERTY_BOX(box), labeltext, true);
  } else {
- GtkWidget* label = gtk_label_new(text);
+ GtkWidget* label = gtk_label_new(labeltext);
  gtk_widget_set_name(label, "text");
  gtk_label_set_use_markup(GTK_LABEL(label), allow_markup);
  gtk_label_set_xalign(GTK_LABEL(label), 0);
@@ -536,6 +559,7 @@
  if(node == NULL) {
  return FALSE;
  }
+ char* nodetext = node->text[0];

  GtkWidget* parent;
  if(node->action_count > 1 && !no_actions) {
@@ -543,7 +567,7 @@
  g_signal_connect(parent, "activate", G_CALLBACK(expand), NULL);
  GtkWidget* box;
  if(node->builder == NULL) {
- box = create_label(node->mode, node->text[0], node->search_text,
node->actions[0]);
+ box = create_label(node->mode, nodetext, node->search_text, node->actions[0]);
  } else {
  box = GTK_WIDGET(node->builder->box);
  setup_label(node->builder->mode->name, WOFI_PROPERTY_BOX(box));
@@ -570,7 +594,7 @@
  }
  } else {
  if(node->builder == NULL) {
- parent = create_label(node->mode, node->text[0], node->search_text,
node->actions[0]);
+ parent = create_label(node->mode, nodetext, node->search_text,
node->actions[0]);
  } else {
  parent = GTK_WIDGET(node->builder->box);
  setup_label(node->builder->mode->name, WOFI_PROPERTY_BOX(parent));
@@ -1234,7 +1258,10 @@
  }

  int fds[2];
- pipe(fds);
+ if (pipe(fds) == -1) {
+ perror("pipe broken");
+ exit(EXIT_FAILURE);
+ }
  if(fork() == 0) {
  close(fds[1]);
  dup2(fds[0], STDIN_FILENO);
@@ -1244,7 +1271,9 @@
  }
  close(fds[0]);

- write(fds[1], action, strlen(action));
+ if (!(write(fds[1], action, strlen(action)) == 0)) {
+ printf("fd pipe failed to write");
+ }

  close(fds[1]);

@@ -1674,6 +1703,8 @@
  char* monitor = map_get(config, "monitor");
  char* layer = config_get(config, "layer", "top");
  copy_exec = config_get(config, "copy_exec", "wl-copy");
+
+ pre_display_cmd = map_get(config, "pre_display_cmd");

  keys = map_init_void();
```

— Regards, Rolf Vidar Mazunki Hoksaas
Scoopta
Details
Message ID
<67ab1b22-76cd-30c9-0086-5f85cd5ac08c@scoopta.email>
In-Reply-To
<CAGn0Psw1jF_AjkUVbFf8kjBknUQ_eN1Oukd4+rDYg_5rmYJA0A@mail.gmail.com> (view parent)
DKIM signature
pass
Download raw message
Ok, there are a couple issues with this. The first issue of which is 
this is just a patch generated from hg diff and then pasted into an 
email which I cannot push. You need to either use the patchbomb 
extension as the readme specifies and is documented here 
https://man.sr.ht/hg.sr.ht/email.md or generate the patch with hg export 
and then attach it as a file to your email. hg diff does not generate an 
importable and pushable patch and if you copy and paste it into your 
mail client it will be mangled and unusable anyway.

The next issue with this is the same issue I had with the last patch 
which was submitted, if you add command line flags you must also add the 
corresponding documentation to the man pages. Specifically wofi(1) for 
the command line option and since all command line options are 
represented internally by config options also wofi(5).

One other comment I want to make, I don't like shoving a 1k char array 
on the stack to hold the label text. It's sort of an arbitrary limiter 
that while should never be exceeded is still very much arbitrary. Most 
of the other places in the wofi code base avoid making guesses about 
size when dealing with files/pipes. There's only a handful of places 
where guesses about size are made(mostly when converting integers to 
strings) and honestly even those should be taken out in favor of a more 
dynamic approach. I suppose practically it doesn't matter seeing as 
you're likely to run into other issues with a label that long anyway but 
I'd prefer not to have an arbitrary limitation because of a statically 
sized buffer.

Overall this is an interesting idea which I unfortunately cannot test 
due to the mangled patch. I assume this works with all modes(not just 
dmenu) correctly? If it doesn't then that needs to be fixed. I can't see 
this as being useful outside of dmenu but unless you put it in the dmenu 
mode source it must work with all modes correctly as core wofi is really 
just an agnostic menuing program.
Reply to thread Export thread (mbox)