yad icon indicating copy to clipboard operation
yad copied to clipboard

--list --dclick-action drops empty values

Open step- opened this issue 5 months ago • 9 comments

When I use --list --dclick-action and the list includes some empty values, the parameters of the dclick-action command are missing the empty values.

yad version 14.1

printf '%s\n' A 1 2 B 1 '' C '' '' D '' 2 | yad --height=200 --list --column={1..3} --print-all --dclick-action='sh -c "set -- %s; echo argc = $#" --'

Below I have rearranged list output and double-click output side by side. I expected to see "argc = 3" for all rows A through D, but clearly the click action drops empty cells.

 A|1|2| argc = 3
 B|1||  argc = 2
 C|||   argc = 1
 D||2|  argc = 2

Using "$@" instead of %s did not help. Adding --quoted-output did not help (although it shouldn't be necessary to use quoted output to get the correct number of arguments).

step- avatar Jul 26 '25 18:07 step-

Works with spaces

printf '%s\n' A 1 2 B 1 ' ' C ' ' ' ' D ' ' 2 | yad --height=200 --list --column={1..3} --print-all --dclick-action='sh -c "set -- %s; echo \"argc = \$# argv = \\\"\$1\\\" \\\"\$2\\\" \\\"\$3\\\"\""'

If you set the zero width space and remove it after it could work, hacky though.

printf '%s\n' A 1 2 B 1 $'\xe2\x80\x8b' C $'\xe2\x80\x8b' $'\xe2\x80\x8b' D $'\xe2\x80\x8b' 2 | yad --height=200 --list --column={1..3} --print-all --dclick-action='sh -c "set -- %s; col1=$(echo \"$1\" | sed \"s/\xe2\x80\x8b//g\"); col2=$(echo \"$2\" | sed \"s/\xe2\x80\x8b//g\"); col3=$(echo \"$3\" | sed \"s/\xe2\x80\x8b//g\"); echo \"argc = $# argv = \\\"$col1\\\" \\\"$col2\\\" \\\"$col3\\\"\""'

Misko-2083 avatar Aug 03 '25 22:08 Misko-2083

Thank you for your comment. I am aware that it works if the value is not empty. To be clear, by "empty" I mean a string without any content. Invisible and non-printable characters count as content.

step- avatar Aug 04 '25 13:08 step-

Ah, alright then found the bug https://github.com/v1cont/yad/blob/5405c318473e576cfdb22a64d60fdabf658a8053/src/list.c#L751

      if (val)
        {
          g_string_append_printf (str, "%s ", val);
          g_free (val);
        }

This skips columns when val == NULL (or empty string if cell_get_data returns NULL for empty cells), which is why you're missing empty columns in the output.

We could append a placeholder like '' even if the cell is empty on NULL:

      if (val && *val)
        {
          g_string_append_printf (str, "%s ", val);
          g_free (val);
        }
      else
        {
          g_string_append (str, "\\\'\\\' ");
        }

It would work like this

printf '%s\n' A 1 2 B 1 '' C '' '' D '' 2 | yad --height=200 --list --column={1..3} --print-all --dclick-action='sh -c "set -- %s; echo \"argc = \$# argv = \"$1\" \"$2\" \"$3\"\""'
argc = 3 argv = A 1 2
argc = 3 argv = B 1 ''
argc = 3 argv = C '' ''
argc = 3 argv = D '' 2

Or maybe we could also quote everything for safety:

g_string_append_printf (str, "\\\'%s\\\' ", val);

Result:

argc = 3 argv = 'A' '1' '2'
argc = 3 argv = 'B' '1' ''
argc = 3 argv = 'C' '' ''
argc = 3 argv = 'D' '' '2'

Misko-2083 avatar Aug 04 '25 14:08 Misko-2083

Good that you found where the problem is. How to fix this is, hmm, unclear to me. The placeholder idea is straighforward but it ends up misrepresenting the empty string, which is the true value of the field, with the string representation of the placeholder. Quoting everything is quite arbitrary and a breaking change for existing scripts. Instead I think that extending the --quoted-output option to all list action commands would make sense, and provide a method for the user to handle empty values. Perhaps @v1cont would prefer not to reuse --quoted-output but to come up with a new option name to quote the action command list.

step- avatar Aug 04 '25 16:08 step-

Since quoting would break scripts, it's best to add a new option to define a separator. That way it is legacy safe and future proof.

For stuctured data in shell scripts it's best to use unit separator \x1F ASCII 31. New option --dclick-separator would be best.

--dclick-separator=unit    # Use \x1F
--dclick-separator=space   # (default, legacy behavior)
--dclick-separator=pipe
--dclick-separator=newline

Then dclick action would look like:

--dclick-action='sh -c "IFS=$'\''\x1F'\''; set -- %s; echo $1 $2 $3; echo argc=$#"' --
# or with readarray (bash)
--dclick-action='sh -c "IFS=$'\''\x1F'\'' read -ra row <<< \"%s\"; echo ${#row[@]} fields: ${row[0]}, ${row[1]}"'

Misko-2083 avatar Aug 04 '25 18:08 Misko-2083

It seems like a good idea. Adding to your idea, and guessing that this issue affects all list action options, the new separator option could be named --action-separator and apply to --dclick-action, --select-action, and --row-action altogether. Or do you think that a different separator for each action type would be needed, that is, --dclick-separator, --select-(action-)separator and --row-(action-)separator ?

step- avatar Aug 04 '25 18:08 step-

That's right. It's easier to maintain one option. Maybe even as a global option. It can possibly be reused for other dialogs and widgets like btn and fbtn in a form dialog.

Misko-2083 avatar Aug 07 '25 15:08 Misko-2083

well, --quoted-output is only about output, not for handlers. when i implement handlers for users actions, i supposed that undefined arguments will be specified with single quotes in command line or such. expanding field values as a rest of command line is only a failover. maybe it should be mentioned in a documentation (mea culpa)

v1cont avatar Oct 02 '25 17:10 v1cont

Hi Victor, good to hear from you! I understand your line of reasoning, and mea culpa is well taken. If you have time to address this issue, this thread offers some proposals.

I opened this issue after writing a script that handles data tables containing empty values. The script works around the NA values by assigning and using a special NA variable. However, I can assure you that it's a real pain to handle, because every list row must be scrutinized to replace empty cells with $NA, likewise the form's output must be cleared of such $NA. It adds a lot of complications to the script.

Using quotes to represent empty values amounts to setting NA="''" or NA='""' instead of handling an empty value.

printf '%s\n' A \'1 2\' B \"1 2\" C '""' "''" D '' 2 | yad --height=200 --list --column={1..3} --print-all --dclick-action='sh -c "set -- %s; echo argc = $#"'
A|'1|2'|
B|"1|2"|
C|""|''|
D||2|

step- avatar Oct 03 '25 09:10 step-