Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: form symbolic ID #213

Closed
wants to merge 2 commits into from
Closed

Conversation

step-
Copy link
Contributor

@step- step- commented Jan 12, 2023

FORM SYMBOLIC ID

The main idea is to add support for symbolic IDs, such as @name, where one can already use ordinal IDs, such as %N, in a form. Similarly for command output redirection: add support for @name: where %N: can be used.

This commit adds two new features to forms:

    --form --use-output-prefix[=PREFIX] --field=label!tooltip:type@ID

Example:

--form --use-output-prefix --field=Number:num@NUMBER 10

Output:

NUMBER=10|

Can be combined with --quoted-output

--form --quoted-output --separator="; " --use-output-prefix="%@ <- " \
	--field="R string:@r_string" "hello" --field= ""

Output:

r_string <- 'hello'; nul=''

Fixed string "nul" is used automatically for any undeclared @id.

yad --form --use-output-prefix --separator=" " --field=:@name test > /tmp/data.sh &&
        . /tmp/data.sh && echo "name=$name"

yad --form --use-output-prefix --separator=$'\n' \
        --field='code:ro' 'declare -A a' \
        --field=':@a[ka]' A --field=':@a[kb]' B \
        --field='code:ro' 'printf %s\\n "${a[@]}"' |
        bash -x
--form --field=label!tooltip:type[@ID]

Example:

--form --field='+1:fbtn@B' '@echo @N:$((@N+1))' --field=':num@N' 1 --use-interp

Can be escaped with @id to avoid expansion
Can be mixed with %N and ^N: but not recommended; better use one or the other

Wherever the use of symbolic references (@id) vs ordinal references (%N) simplifies coding or maintaining the code.

Form options
    --field=LABEL[!TOOLTIP][:TYPE[@ID]]
...
    --use-output-prefix[=PREFIX]
           Prefix output field value with PREFIX. Default PREFIX is %@=. If %@ is included
           in PREFIX, it will be replaced by the field's @ID (without the leading "@") if
           defined, otherwise by fixed string "nul".
...
           BTN - button field. Label text may be formatted as LABEL[!ICON[!TOOLTIP]]
           where `!' is an item separator. LABEL is the text of button label or yad stock
           id. ICON is a button icon (stock id or file name). TOOLTIP is the text of an
           optional help popup tooltip. Initial value is a command which is started when
           the button is clicked. Special symbols %N (percent followed by a number) in
           command will be replaced by the value of the Nth field. If command starts with
           @, the output of com‐ mand will be parsed and lines that start with M: (a
           number followed by colon) will set the new value of the Mth field.  @ID can
           be used instead of %N and M:.  A quoting style for value when sh -c is used -
           single quotes around command and double quotes around -c argument.

In option.c, setting the default output prefix was similar to setting the default interpreter, so I followed that example. The setter function and the new options are:

static gboolean set_form_output_prefix (const gchar *, const gchar *, gpointer, GError **);

options.form_data.use_output_prefix = FALSE;
options.form_data.output_prefix = "%@=";

Modifications of existing functions:

  • IDs are parsed and stored in function add_field() as usual.
  • PREFIX is inserted in function form_print_field(). The code is straightforward, although it affects each case of the main switch.

Field ID is stored in struct YadFields as member atid. Mind that atid stores "@id" not "ID".

typedef struct {
  gchar *name;
  gchar *tip;
  YadFieldType type;
  gchar *atid;
} YadField;

IDs, if any, are expanded into their corresponding %N and ^N: forms, which are then processed as usual with the existing code. Two new functions in form.c perform ID expansion: preprocess_atid() and preprocess_cb() (callback). Expansion is based on regular expressions.

Function preprocess_atid() is called twice.
First in expand_action() before the latter expands %N into field value:

  gboolean needs_free = preprocess_atid (command, "\\\\%1$s|%1$s\\b:?", &cmd);
  • needs_free indicates the need to call g_free() on *cmd
  • command (input) is the field value as specified by the user
  • cmd (output) is the same value with %N standing for @ID
  • %1$s in the regular expression stands for %N Of course N={1,...M}.

Second in parse_cmd_output() before the latter expands ^N: into output redirection:

  gboolean needs_free = preprocess_atid (text, "\\\\%1$s|^%1$s:", &data);
  • text (input) is the raw command output
  • data (output) is the same text with N: standing for ^@ID:

This trace shows it all, @id => %N value expansion, @id: => N: redirection expansion, @id escaping.

INCREMENT BY 1 AND REPROGRAM BUTTON ACTION

export YAD_OPTIONS="--use-interp='dash -xc \"%s\"'"
yad=src/yad

$yad --form --field='+1:fbtn@B' '@echo @N:$((@N+1)); '"echo '@B:@echo @N:\$((\@N+1))'" --field=res:num@N 1

$yad --form --field='+1:fbtn@B' '@echo @N:$((@N+1)); '"printf '@'; printf 'B:@echo '; printf @; printf 'N:\$((\@N+1))'; echo" --field=res:num@N 1

command and cmd refer to before/after the call to preprocess_atid() in expand_action(). text and data refer to before/after the call to preprocess_atid() in parse_cmd_output().

┌─────────────────────────────────────────────────────────┐  ·  ┌─────────────────────────────────────────────────────────┐
│  FIRST MOUSE CLICK 1+1                                  │  ·  │  FIRST MOUSE CLICK 1+1                                  │
└─────────────────────────────────────────────────────────┘  ·  └─────────────────────────────────────────────────────────┘
command( echo @N:$((@N+1)); echo '@B:@echo @N:$((\@N+1))' )  !  command( echo @N:$((@N+1)); printf '@'; printf 'B:@echo '; printf @; printf 'N:$((\@N+1))'; echo )
cmd    ( echo @N:$((%2+1)); echo '@B:@echo @N:$((@N+1))' )   !  cmd    ( echo @N:$((%2+1)); printf '@'; printf 'B:@echo '; printf @; printf 'N:$((@N+1))'; echo )
+ echo @N:2                                                  ·  + echo @N:2
+ echo @B:@echo @N:$((@N+1))                                 !  + printf @
                                                             >  + printf 'B:@echo '
                                                             >  + printf @
                                                             >  + printf N:$((@N+1))
                                                             >  + echo
text   ( @N:2                                                ·  text   ( @N:2
@B:@echo @N:$((@N+1))                                        ·  @B:@echo @N:$((@N+1))
 )                                                           ·   )
data   ( 2:2                                                 ·  data   ( 2:2
1:@echo @N:$((@N+1))                                         ·  1:@echo @N:$((@N+1))
 )                                                           ·   )
┌─────────────────────────────────────────────────────────┐  ·  ┌─────────────────────────────────────────────────────────┐
│  SECOND MOUSE CLICK 2+1                                 │  ·  │  SECOND MOUSE CLICK 2+1                                 │
└─────────────────────────────────────────────────────────┘  ·  └─────────────────────────────────────────────────────────┘
command( echo @N:$((@N+1)) )                                 ·  command( echo @N:$((@N+1)) )
cmd    ( echo @N:$((%2+1)) )                                 ·  cmd    ( echo @N:$((%2+1)) )
+ echo @N:3                                                  ·  + echo @N:3
text   ( @N:3                                                ·  text   ( @N:3
 )                                                           ·   )
data   ( 2:3                                                 ·  data   ( 2:3
 )                                                           ·   )

FORM SYMBOLIC ID
================

The main idea is to add support for symbolic IDs, such as `@name`, where one can already use ordinal IDs, such as `%N`, in a form.
Similarly for command output redirection: add support for `@name:` where `%N:` can be used.

This commit adds two new features to forms:

        --form --use-output-prefix[=PREFIX] --field=label!tooltip:type@ID

Example:

	--form --use-output-prefix --field=Number:num@NUMBER 10
Output:

	NUMBER=10|

Can be combined with --quoted-output

	--form --quoted-output --separator="; " --use-output-prefix="%@ <- " \
		--field="R string:@r_string" "hello" --field= ""

Output:

	r_string <- 'hello'; nul=''

Fixed string "nul" is used automatically for any undeclared @id.

```sh
yad --form --use-output-prefix --separator=" " --field=:@name test > /tmp/data.sh &&
        . /tmp/data.sh && echo "name=$name"

yad --form --use-output-prefix --separator=$'\n' \
        --field='code:ro' 'declare -A a' \
        --field=':@A[ka]' A --field=':@A[kb]' B \
        --field='code:ro' 'printf %s\\n "${a[@]}"' |
        bash -x
```

	--form --field=label!tooltip:type[@id]

Example:

	--form --field='+1:fbtn@B' '@echo @n:$((@n+1))' --field=':num@N' 1 --use-interp

Can be escaped with \@id to avoid expansion
Can be mixed with %N and ^N: but not recommended; better use one or the other

Wherever the use of symbolic references (@id) vs ordinal references (%N) simplifies coding or maintaining the code.

```
Form options
    --field=LABEL[!TOOLTIP][:TYPE[@id]]
...
    --use-output-prefix[=PREFIX]
           Prefix output field value with PREFIX. Default PREFIX is %@=. If %@ is included
           in PREFIX, it will be replaced by the field's @id (without the leading "@") if
           defined, otherwise by fixed string "nul".
...
           BTN - button field. Label text may be formatted as LABEL[!ICON[!TOOLTIP]]
           where `!' is an item separator. LABEL is the text of button label or yad stock
           id. ICON is a button icon (stock id or file name). TOOLTIP is the text of an
           optional help popup tooltip. Initial value is a command which is started when
           the button is clicked. Special symbols %N (percent followed by a number) in
           command will be replaced by the value of the Nth field. If command starts with
           @, the output of com‐ mand will be parsed and lines that start with M: (a
           number followed by colon) will set the new value of the Mth field.  @id can
           be used instead of %N and M:.  A quoting style for value when sh -c is used -
           single quotes around command and double quotes around -c argument.
```

In option.c, setting the default output prefix was similar to setting the default interpreter, so I followed that example.
The setter function and the new options are:

```c
static gboolean set_form_output_prefix (const gchar *, const gchar *, gpointer, GError **);

options.form_data.use_output_prefix = FALSE;
options.form_data.output_prefix = "%@=";
```

Modifications of existing functions:
* IDs are parsed and stored in function `add_field()` as usual.
* PREFIX is inserted in function `form_print_field()`.  The code is straightforward, although it affects each `case` of the main `switch`.

Field ID is stored in struct `YadFields` as member `atid`. Mind that `atid` stores "@id" not "ID".

```c
typedef struct {
  gchar *name;
  gchar *tip;
  YadFieldType type;
  gchar *atid;
} YadField;
```

IDs, if any, are expanded into their corresponding `%N` and ^`N:` forms, which are then processed as usual with the existing code.
Two new functions in form.c perform ID expansion: `preprocess_atid()` and `preprocess_cb()` (callback).
Expansion is based on regular expressions.

Function `preprocess_atid()` is called twice.
First in `expand_action()` before the latter expands `%N` into field value:

```c
  gboolean needs_free = preprocess_atid (command, "\\\\%1$s|%1$s\\b:?", &cmd);
```

* `needs_free` indicates the need to call `g_free()` on `*cmd`
* `command` (input) is the field value as specified by the user
* `cmd` (output) is the same value with `%N` standing for `@ID`
* `%1$s` in the regular expression stands for `%N`
Of course N={1,...M}.

Second in `parse_cmd_output()` before the latter expands ^`N:` into output redirection:

```c
  gboolean needs_free = preprocess_atid (text, "\\\\%1$s|^%1$s:", &data);
```

* `text` (input) is the raw command output
* `data` (output) is the same text with `N:` standing for ^`@ID:`

This trace shows it all, @id => %N value expansion, @id: => N: redirection expansion, \@id escaping.

**INCREMENT BY 1 AND REPROGRAM BUTTON ACTION**

```sh
export YAD_OPTIONS="--use-interp='dash -xc \"%s\"'"
yad=src/yad

$yad --form --field='+1:fbtn@B' '@echo @n:$((@n+1)); '"echo '@b:@echo @n:\$((\@n+1))'" --field=res:num@N 1

$yad --form --field='+1:fbtn@B' '@echo @n:$((@n+1)); '"printf '@'; printf 'B:@echo '; printf @; printf 'N:\$((\@n+1))'; echo" --field=res:num@N 1
```

`command` and `cmd` refer to before/after the call to `preprocess_atid()` in `expand_action()`.
`text` and `data` refer to before/after the call to `preprocess_atid()` in `parse_cmd_output()`.

```
┌─────────────────────────────────────────────────────────┐  ·  ┌─────────────────────────────────────────────────────────┐
│  FIRST MOUSE CLICK 1+1                                  │  ·  │  FIRST MOUSE CLICK 1+1                                  │
└─────────────────────────────────────────────────────────┘  ·  └─────────────────────────────────────────────────────────┘
command( echo @n:$((@n+1)); echo '@b:@echo @n:$((\@n+1))' )  !  command( echo @n:$((@n+1)); printf '@'; printf 'B:@echo '; printf @; printf 'N:$((\@n+1))'; echo )
cmd    ( echo @n:$((%2+1)); echo '@b:@echo @n:$((@n+1))' )   !  cmd    ( echo @n:$((%2+1)); printf '@'; printf 'B:@echo '; printf @; printf 'N:$((@n+1))'; echo )
+ echo @n:2                                                  ·  + echo @n:2
+ echo @b:@echo @n:$((@n+1))                                 !  + printf @
                                                             >  + printf 'B:@echo '
                                                             >  + printf @
                                                             >  + printf N:$((@n+1))
                                                             >  + echo
text   ( @n:2                                                ·  text   ( @n:2
@b:@echo @n:$((@n+1))                                        ·  @b:@echo @n:$((@n+1))
 )                                                           ·   )
data   ( 2:2                                                 ·  data   ( 2:2
1:@echo @n:$((@n+1))                                         ·  1:@echo @n:$((@n+1))
 )                                                           ·   )
┌─────────────────────────────────────────────────────────┐  ·  ┌─────────────────────────────────────────────────────────┐
│  SECOND MOUSE CLICK 2+1                                 │  ·  │  SECOND MOUSE CLICK 2+1                                 │
└─────────────────────────────────────────────────────────┘  ·  └─────────────────────────────────────────────────────────┘
command( echo @n:$((@n+1)) )                                 ·  command( echo @n:$((@n+1)) )
cmd    ( echo @n:$((%2+1)) )                                 ·  cmd    ( echo @n:$((%2+1)) )
+ echo @n:3                                                  ·  + echo @n:3
text   ( @n:3                                                ·  text   ( @n:3
 )                                                           ·   )
data   ( 2:3                                                 ·  data   ( 2:3
 )                                                           ·   )
```
@step-
Copy link
Contributor Author

step- commented Jan 12, 2023

highlighted diff of the trace

Diff

and a version of Frontend-for-find script (with #212 included) where I modified %N and N: with symbolic IDs, just for testing.

Frontend-for-find.sh.txt

@step-
Copy link
Contributor Author

step- commented Jan 12, 2023

FYI, I don't have any more PRs to submit.

Master commit 1d402f7 introduced a merge conflict with this PR.
This commit makes the PR mergeable again.
step- added a commit to step-/yad that referenced this pull request Feb 9, 2023
An adapted version of this commit is also pending as PR v1cont/yad#213

FORM SYMBOLIC ID
================

The main idea is to add support for symbolic IDs, such as `@name`, where one can already use ordinal IDs, such as `%N`, in a form.
Similarly for command output redirection: add support for `@name:` where `%N:` can be used.

This commit adds two new features to forms:

	--form --use-output-prefix[=PREFIX] --field=label!tooltip:type@ID

Example:

	--form --use-output-prefix --field=Number:num@NUMBER 10
Output:

	NUMBER=10|

Can be combined with --quoted-output

	--form --quoted-output --separator="; " --use-output-prefix="%@ <- " \
		--field="R string:@r_string" "hello" --field= ""

Output:

	r_string <- 'hello'; nul=''

Fixed string "nul" is used automatically for any undeclared @id.

```sh
yad --form --use-output-prefix --separator=" " --field=:@name test > /tmp/data.sh &&
        . /tmp/data.sh && echo "name=$name"

yad --form --use-output-prefix --separator=$'\n' \
        --field='code:ro' 'declare -A a' \
        --field=':@A[ka]' A --field=':@A[kb]' B \
        --field='code:ro' 'printf %s\\n "${a[@]}"' |
        bash -x
```

	--form --field=label!tooltip:type[@id]

Example:

	--form --field='+1:fbtn@B' '@echo @n:$((@n+1))' --field=':num@N' 1 --use-interp

Can be escaped with \@id to avoid expansion
Can be mixed with %N and ^N: but not recommended; better use one or the other

Wherever the use of symbolic references (@id) vs ordinal references (%N) simplifies coding or maintaining the code.

```
Form options
    --field=LABEL[!TOOLTIP][:TYPE[@id]]
...
    --use-output-prefix[=PREFIX]
           Prefix output field value with PREFIX. Default PREFIX is %@=. If %@ is included
           in PREFIX, it will be replaced by the field's @id (without the leading "@") if
           defined, otherwise by fixed string "nul".
...
           BTN - button field. Label text may be formatted as LABEL[!ICON[!TOOLTIP]]
           where `!' is an item separator. LABEL is the text of button label or yad stock
           id. ICON is a button icon (stock id or file name). TOOLTIP is the text of an
           optional help popup tooltip. Initial value is a command that runs when
           the button is clicked. Special symbols %N (percent followed by a number) in
           command will be replaced by the value of the Nth field. If command starts with
           @, the output of command will be parsed and lines that start with M: (a
           number followed by colon) will set the new value of the Mth field.  @id can
           be used instead of %N and M:.  A quoting style for value when sh -c is used -
           single quotes around command and double quotes around -c argument.
```

In option.c, setting the default output prefix was similar to setting the default interpreter, so I followed that example.
The setter function and the new options are:

```c
static gboolean set_form_output_prefix (const gchar *, const gchar *, gpointer, GError **);

options.form_data.use_output_prefix = FALSE;
options.form_data.output_prefix = "%@=";
```

Modifications of existing functions:
* IDs are parsed and stored in function `add_field()` as usual.
* PREFIX is inserted in function `form_print_field()`.  The code is straightforward, although it affects each `case` of the main `switch`.

Field ID is stored in struct `YadFields` as member `atid`. Mind that `atid` stores "@id" not "ID".

```c
typedef struct {
  gchar *name;
  gchar *tip;
  YadFieldType type;
  gchar *atid;
} YadField;
```

IDs, if any, are expanded into their corresponding `%N` and ^`N:` forms, which are then processed as usual with the existing code.
Two new functions in form.c perform ID expansion: `preprocess_atid()` and `preprocess_cb()` (callback).
Expansion is based on regular expressions.

Function `preprocess_atid()` is called twice.
First in `expand_action()` before the latter expands `%N` into field value:

```c
  gboolean needs_free = preprocess_atid (command, "\\\\%1$s|%1$s\\b:?", &cmd);
```

* `needs_free` indicates the need to call `g_free()` on `*cmd`
* `command` (input) is the field value as specified by the user
* `cmd` (output) is the same value with `%N` standing for `@ID`
* `%1$s` in the regular expression stands for `%N`
Of course N={1,...M}.

Second in `parse_cmd_output()` before the latter expands ^`N:` into output redirection:

```c
  gboolean needs_free = preprocess_atid (text, "\\\\%1$s|^%1$s:", &data);
```

* `text` (input) is the raw command output
* `data` (output) is the same text with `N:` standing for ^`@ID:`

This trace shows it all, @id => %N value expansion, @id: => N: redirection expansion, \@id escaping.

**INCREMENT BY 1 AND REPROGRAM BUTTON ACTION**

```sh
export YAD_OPTIONS="--use-interp='dash -xc \"%s\"'"
yad=src/yad

$yad --form --field='+1:fbtn@B' '@echo @n:$((@n+1)); '"echo '@b:@echo @n:\$((\@n+1))'" --field=res:num@N 1

$yad --form --field='+1:fbtn@B' '@echo @n:$((@n+1)); '"printf '@'; printf 'B:@echo '; printf @; printf 'N:\$((\@n+1))'; echo" --field=res:num@N 1
```

`command` and `cmd` refer to before/after the call to `preprocess_atid()` in `expand_action()`.
`text` and `data` refer to before/after the call to `preprocess_atid()` in `parse_cmd_output()`.

```
┌─────────────────────────────────────────────────────────┐  ·  ┌─────────────────────────────────────────────────────────┐
│  FIRST MOUSE CLICK 1+1                                  │  ·  │  FIRST MOUSE CLICK 1+1                                  │
└─────────────────────────────────────────────────────────┘  ·  └─────────────────────────────────────────────────────────┘
command( echo @n:$((@n+1)); echo '@b:@echo @n:$((\@n+1))' )  !  command( echo @n:$((@n+1)); printf '@'; printf 'B:@echo '; printf @; printf 'N:$((\@n+1))'; echo )
cmd    ( echo @n:$((%2+1)); echo '@b:@echo @n:$((@n+1))' )   !  cmd    ( echo @n:$((%2+1)); printf '@'; printf 'B:@echo '; printf @; printf 'N:$((@n+1))'; echo )
+ echo @n:2                                                  ·  + echo @n:2
+ echo @b:@echo @n:$((@n+1))                                 !  + printf @
                                                             >  + printf 'B:@echo '
                                                             >  + printf @
                                                             >  + printf N:$((@n+1))
                                                             >  + echo
text   ( @n:2                                                ·  text   ( @n:2
@b:@echo @n:$((@n+1))                                        ·  @b:@echo @n:$((@n+1))
 )                                                           ·   )
data   ( 2:2                                                 ·  data   ( 2:2
1:@echo @n:$((@n+1))                                         ·  1:@echo @n:$((@n+1))
 )                                                           ·   )
┌─────────────────────────────────────────────────────────┐  ·  ┌─────────────────────────────────────────────────────────┐
│  SECOND MOUSE CLICK 2+1                                 │  ·  │  SECOND MOUSE CLICK 2+1                                 │
└─────────────────────────────────────────────────────────┘  ·  └─────────────────────────────────────────────────────────┘
command( echo @n:$((@n+1)) )                                 ·  command( echo @n:$((@n+1)) )
cmd    ( echo @n:$((%2+1)) )                                 ·  cmd    ( echo @n:$((%2+1)) )
+ echo @n:3                                                  ·  + echo @n:3
text   ( @n:3                                                ·  text   ( @n:3
 )                                                           ·   )
data   ( 2:3                                                 ·  data   ( 2:3
 )                                                           ·   )
```
@v1cont v1cont closed this Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants