diff options
-rw-r--r-- | ChangeLog.adoc | 1 | ||||
-rw-r--r-- | doc/de/weechat_user.de.adoc | 151 | ||||
-rw-r--r-- | doc/en/weechat_user.en.adoc | 131 | ||||
-rw-r--r-- | doc/fr/weechat_user.fr.adoc | 132 | ||||
-rw-r--r-- | doc/it/weechat_user.it.adoc | 127 | ||||
-rw-r--r-- | doc/ja/weechat_user.ja.adoc | 149 | ||||
-rw-r--r-- | doc/pl/weechat_user.pl.adoc | 147 | ||||
-rw-r--r-- | doc/sr/weechat_user.sr.adoc | 139 | ||||
-rw-r--r-- | src/plugins/trigger/trigger-callback.c | 140 | ||||
-rw-r--r-- | src/plugins/trigger/trigger-callback.h | 2 | ||||
-rw-r--r-- | src/plugins/trigger/trigger.c | 90 | ||||
-rw-r--r-- | src/plugins/trigger/trigger.h | 13 | ||||
-rw-r--r-- | tests/unit/plugins/trigger/test-trigger.cpp | 160 |
13 files changed, 1075 insertions, 307 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc index 79ace8088..1ab59c1a8 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -21,6 +21,7 @@ https://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes] New features:: * core: allow command `/toggle` to create option before setting the value, if allowed in the section (issue #1837) + * trigger: add regex command "y" to translate chars, set default regex command to "s" (regex replace) (issue #1510) Bug fixes:: diff --git a/doc/de/weechat_user.de.adoc b/doc/de/weechat_user.de.adoc index f7c86c5cf..305a3dd6e 100644 --- a/doc/de/weechat_user.de.adoc +++ b/doc/de/weechat_user.de.adoc @@ -4942,19 +4942,120 @@ zu werden: ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) ---- +// TRANSLATION MISSING [[trigger_regex]] -=== reguläre Ausdrücke +=== Regular expression -Reguläre Ausdrücke werden verwendet um Variablen in einem Callback Hashtable zu ändern. +The regular expression is used to change variables in callback hashtable. -Das Format ist: "/regex/replace" oder "/regex/replace/var" (wobei _var_ eine -Variable eines Hashtable darstellt). +Format is one of the following: -Falls _var_ in der Hashtabelle nicht existieren sollte, wird diese automatisch mit einem -leeren Wert angelegt. Damit kann man temporär benutzerspezifische Variablen erstellen. +---- +/string1/string2 +s/string1/string2 +s/string1/string2/var +y/string1/string2 +y/string1/string2/var +---- + +Fields: + +* `s` or `y`: a letter with the command; if missing, default command is `s` + and the first char is then used as the delimiter: +** `s`: regex replacement: first string is a regular expression, second string + is the replacement for every matching string +** `y`: chars translation: first string is a set of characters that are replaced + by the characters in the second string; once evaluated, each string must have + exactly the same number of UTF-8 chars +* `/`: the regex delimiter; the char "/" can be replaced by any char + (one or more identical chars) +* `string1`: the first string (use depends on the command) +* `string2`: the second string (use depends on the command) +* `var`: the hashtable variable to update + +Many regular expressions can be separated by a space, for example: + +---- +s/regex1/replace1/var1 y/abcdef/ABDDEF/var2 +---- + +// TRANSLATION MISSING +[[trigger_regex_replace]] +==== Regex replace + +For the command `s`, the format is: `s/regex/replace` or `s/regex/replace/var` +(where _var_ is a variable of the hashtable). + +As `s` is the default command, it can be omitted, so `/regex/replace` is also +valid (but the first char, which is the delimiter, must not be a letter). + +Matching groups can be used in _replace_: + +* `+${re:0}+` to `+${re:99}+`: `+${re:0}+` is the whole match, `+${re:1}+` to + `+${re:99}+` are groups captured +* `+${re:+}+`: the last match (with highest number) +* `+${hide:c,${re:N}}+`: match "N" with all chars replaced by "c" + (example: `+${hide:*,${re:2}}+` is the group #2 with all chars replaced by + `+*+`). + +Example: use bold for words between `+*+`: + +---- +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +---- + +Example: default trigger _server_pass_ uses this regular expression to hide +password in commands `/server` and `/connect` (chars in passwords are replaced +by `+*+`): + +---- +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +---- + +[NOTE] +In this example, the delimiter used is "==" because there is a "/" in the +regular expression. + +// TRANSLATION MISSING +[[trigger_regex_translate_chars]] +==== Translate chars + +For the command `y`, the format is: `y/chars1/chars2` or `y/chars1/chars2/var` +(where _var_ is a variable of the hashtable). + +Example: replace "a", "b" and "c" by upper case letter: + +---- +y/abc/ABC/ +---- -Sollte _var_ nicht näher spezifiziert sein, wird die Standard-Variable genutzt, -welche abhängig von dem genutzten Hook ist: +Example: rotate arrows clockwise: + +---- +y/←↑→↓/↑→↓←/ +---- + +Example: convert all letters to lower case: + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Example: shift each letter by one position, preserving case: a→b, b→c … y→z, z→a: + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +// TRANSLATION MISSING +[[trigger_regex_variable]] +==== Variable + +If _var_ does not exist in the hashtable, it is created automatically with an +empty value. This allows to create custom temporary variables. + +If _var_ is not specified, the default variable is used, it depends on hook +type: [width="100%",cols="2,3,7",options="header"] |=== @@ -4978,40 +5079,6 @@ welche abhängig von dem genutzten Hook ist: haben einen Einfluss auf den Wert der vom Trigger zurückgegeben wird und dann von WeeChat genutzt wird. -Mehrere reguläre Ausdrücke können durch ein Leerzeichen voneinander -getrennt werden, zum Beispiel: -"/regex1/replace1/var1 /regex2/replace2/var2". - -Das Zeichen "/" kann durch jedes andere Zeichen ersetzt werden (ein -oder mehrere identische Zeichen). - -Matching groups können in "replace" genutzt werden: - -* `+${re:0}+` bis `+${re:99}+`: `+${re:0}+` um alles zu matchen, `+${re:1}+` bis - `+${re:99}+` um Gruppen zu fangen -* `+${re:+}+`: der letzte match (mit der höchsten Nummer) -* `+${hide:c,${re:N}}+`: match "N" mit allen Zeichen die durch "c" ersetzt wurden - (Beispiel: `+${hide:*,${re:2}}+` ist die group #2 mit allen Zeichen die durch - `+*+` ersetzt wurden). - -Beispiel: nutzte Fettschrift zwischen dem Zeichen `+*+`: - ----- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ----- - -Beispiel: der Standard-Trigger _server_pass_ nutzt folgenden regulären Ausdruck -um ein Passwort in den Befehlen `/server` und `/connect` zu verbergen (die -einzelnen Zeichen des Passwortes werden durch `+*+` ersetzt): - ----- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ----- - -[NOTE] -In diesem Beispiel wird "==" als Trennzeichen verwendet, da ein "/" in -dem regulären Ausdruck genutzt wird. - [[trigger_command]] === Befehl diff --git a/doc/en/weechat_user.en.adoc b/doc/en/weechat_user.en.adoc index 10f23bc78..afe02e2fe 100644 --- a/doc/en/weechat_user.en.adoc +++ b/doc/en/weechat_user.en.adoc @@ -4660,8 +4660,8 @@ A trigger has the following options (names are <<command_weechat_eval,/eval>>). | regex | string -| One or more POSIX extended regular expressions, to change data received in the - hook callback (and some stuff added by trigger plugin), see +| One or more regex "commands" (similar to the `sed` command) to change data + received in the hook callback (and some stuff added by trigger plugin), see <<trigger_regex,regular expression>>. | command | string @@ -4834,42 +4834,47 @@ ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) The regular expression is used to change variables in callback hashtable. -The format is: "/regex/replace" or "/regex/replace/var" (where _var_ is a -variable of the hashtable). +Format is one of the following: -If _var_ does not exist in the hashtable, it is created automatically with an -empty value. This allows to create custom temporary variables. +---- +/string1/string2 +s/string1/string2 +s/string1/string2/var +y/string1/string2 +y/string1/string2/var +---- -If _var_ is not specified, the default variable is used, it depends on hook -type: +Fields: -[width="100%",cols="2,3,7",options="header"] -|=== -| Hook | Default variable | Update allowed ^(1)^ -| signal | tg_signal_data | -| hsignal | | -| modifier | tg_string | tg_string -| line | message | buffer, buffer_name, y, date, date_printed, str_time, tags, notify_level, highlight, prefix, message -| print | tg_message | -| command | tg_argv_eol1 | -| command_run | tg_command | -| timer | tg_remaining_calls | -| config | tg_value | -| focus | | -| info | tg_info | tg_info -| info_hashtable | | all variables received in hashtable -|=== - -[NOTE] -^(1)^ All variables can be updated in the trigger, but only these variables -have an effect on the value returned by the trigger and used by WeeChat. +* `s` or `y`: a letter with the command; if missing, default command is `s` + and the first char is then used as the delimiter: +** `s`: regex replacement: first string is a regular expression, second string + is the replacement for every matching string +** `y`: chars translation: first string is a set of characters that are replaced + by the characters in the second string; once evaluated, each string must have + exactly the same number of UTF-8 chars +* `/`: the regex delimiter; the char "/" can be replaced by any char + (one or more identical chars) +* `string1`: the first string (use depends on the command) +* `string2`: the second string (use depends on the command) +* `var`: the hashtable variable to update Many regular expressions can be separated by a space, for example: -"/regex1/replace1/var1 /regex2/replace2/var2". -The char "/" can be replaced by any char (one or more identical chars). +---- +s/regex1/replace1/var1 y/abcdef/ABDDEF/var2 +---- + +[[trigger_regex_replace]] +==== Regex replace + +For the command `s`, the format is: `s/regex/replace` or `s/regex/replace/var` +(where _var_ is a variable of the hashtable). -Matching groups can be used in "replace": +As `s` is the default command, it can be omitted, so `/regex/replace` is also +valid (but the first char, which is the delimiter, must not be a letter). + +Matching groups can be used in _replace_: * `+${re:0}+` to `+${re:99}+`: `+${re:0}+` is the whole match, `+${re:1}+` to `+${re:99}+` are groups captured @@ -4881,7 +4886,7 @@ Matching groups can be used in "replace": Example: use bold for words between `+*+`: ---- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ---- Example: default trigger _server_pass_ uses this regular expression to hide @@ -4889,13 +4894,73 @@ password in commands `/server` and `/connect` (chars in passwords are replaced by `+*+`): ---- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ---- [NOTE] In this example, the delimiter used is "==" because there is a "/" in the regular expression. +[[trigger_regex_translate_chars]] +==== Translate chars + +For the command `y`, the format is: `y/chars1/chars2` or `y/chars1/chars2/var` +(where _var_ is a variable of the hashtable). + +Example: replace "a", "b" and "c" by upper case letter: + +---- +y/abc/ABC/ +---- + +Example: rotate arrows clockwise: + +---- +y/←↑→↓/↑→↓←/ +---- + +Example: convert all letters to lower case: + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Example: shift each letter by one position, preserving case: a→b, b→c … y→z, z→a: + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +[[trigger_regex_variable]] +==== Variable + +If _var_ does not exist in the hashtable, it is created automatically with an +empty value. This allows to create custom temporary variables. + +If _var_ is not specified, the default variable is used, it depends on hook +type: + +[width="100%",cols="2,3,7",options="header"] +|=== +| Hook | Default variable | Update allowed ^(1)^ +| signal | tg_signal_data | +| hsignal | | +| modifier | tg_string | tg_string +| line | message | buffer, buffer_name, y, date, date_printed, str_time, tags, notify_level, highlight, prefix, message +| print | tg_message | +| command | tg_argv_eol1 | +| command_run | tg_command | +| timer | tg_remaining_calls | +| config | tg_value | +| focus | | +| info | tg_info | tg_info +| info_hashtable | | all variables received in hashtable +|=== + +[NOTE] +^(1)^ All variables can be updated in the trigger, but only these variables +have an effect on the value returned by the trigger and used by WeeChat. + [[trigger_command]] === Command diff --git a/doc/fr/weechat_user.fr.adoc b/doc/fr/weechat_user.fr.adoc index 6085d37d9..5f0198506 100644 --- a/doc/fr/weechat_user.fr.adoc +++ b/doc/fr/weechat_user.fr.adoc @@ -4989,44 +4989,48 @@ ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) L'expression régulière est utilisée pour modifier des variables dans la table de hachage de la fonction de rappel. -Le format est : "/regex/remplacement" ou "/regex/remplacement/var" (où _var_ est -une variable de la table de hachage). +Le format est l'un des suivants : -Si _var_ n'existe pas dans la table de hachage, elle est automatiquement créée -avec une valeur vide. Cela permet de créer des variables temporaires. +---- +/chaîne1/chaîne2 +s/chaîne1/chaîne2 +s/chaîne1/chaîne2/var +y/chaîne1/chaîne2 +y/chaîne1/chaîne2/var +---- -Si _var_ n'est pas spécifiée, la variable par défaut est utilisée, elle dépend -du type de hook : +Champs : -[width="100%",cols="2,3,7",options="header"] -|=== -| Hook | Variable par défaut | Mise à jour autorisée ^(1)^ -| signal | tg_signal_data | -| hsignal | | -| modifier | tg_string | tg_string -| line | message | buffer, buffer_name, y, date, date_printed, str_time, tags, notify_level, highlight, prefix, message -| print | tg_message | -| command | tg_argv_eol1 | -| command_run | tg_command | -| timer | tg_remaining_calls | -| config | tg_value | -| focus | | -| info | tg_info | tg_info -| info_hashtable | | toutes les variables reçues dans la table de hachage -|=== +* `s` ou `y` : une lettre avec la commande ; si manquante, la commande par défaut + est `s` et le premier caractère est alors utilisé comme délimiteur : +** `s` : remplacement par expression régulière : la première chaîne est l'expression + régulière, la seconde chaîne est le remplacement pour chaque chaîne trouvée +** `y` : traduction de caractères : la première chaîne est un ensemble de caractères + qui sont remplacés par les caractères de la seconde chaîne ; une fois évaluée, + chaque chaîne doit contenir exactement le même nombre de caractères UTF-8 +* `/` : le délimiteur d'expression régulière ; le caractère "/" peut être remplacé + par n'importe quel caractère (un ou plusieurs caractères identiques) +* `chaîne1` : la première chaîne (l'utilisation dépend de la commande) +* `chaîne2` : la seconde chaîne (l'utilisation dépend de la commande) +* `var` : la table de hachage avec la variable à mettre à jour -[NOTE] -^(1)^ Toutes les variables peuvent être mises à jour dans le trigger, mais -seulement ces variables ont un effet sur la valeur retournée par le trigger -et utilisée par WeeChat. +Plusieurs expressions régulières peuvent être séparées par un espace, par exemple : + +---- +s/regex1/remplacement1/var1 y/abcdef/ABDDEF/var2 +---- + +[[trigger_regex_replace]] +==== Regex replace -Plusieurs expressions régulières peuvent être séparées par un espace, par -exemple : "/regex1/remplacement1/var1 /regex2/remplacement2/var2". +Pour la commande `s`, le format est : `s/regex/remplacement` ou +`s/regex/remplacement/var` (où _var_ est une variable de la table de hachage). -Le caractère "/" peut être remplacé par tout caractère (un ou plusieurs -caractères identiques). +Comme `s` est la commande par défaut, elle peut être omise, donc `/regex/replace` +est également valide (mais le premier caractère, qui est le délimiteur, ne doit +pas être une lettre). -Les groupes de correspondance peuvent être utilisés dans le "remplacement" : +Les groupes de correspondance peuvent être utilisés dans le _remplacement_ : * `+${re:0}+` à `+${re:99}+` : `+${re:0}+` est la correspondance complète, `+${re:1}+` à `+${re:99}+` sont les groupes capturés @@ -5038,7 +5042,7 @@ Les groupes de correspondance peuvent être utilisés dans le "remplacement" : Exemple : utiliser du gras pour les mots entre `+*+` : ---- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ---- Exemple : le trigger par défaut _server_pass_ utilise cette expression régulière @@ -5046,13 +5050,75 @@ pour cacher le mot de passe dans les commandes `/server` et `/connect` (les caractères des mots de passe sont remplacés par `+*+`) : ---- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ---- [NOTE] Dans cet exemple, le séparateur utilisé est "==" car il y a "/" dans l'expression régulière. +[[trigger_regex_translate_chars]] +==== Translate chars + +Pour la commande `y`, le format est : `y/caractères1/caractères2` ou +`y/caractères1/caractères2/var` (où _var_ est une variable de la table de hachage). + +Exemple : remplacer "a", "b" et "c" par la lettre en majuscules : + +---- +y/abc/ABC/ +---- + +Exemple : faire tourner une flèche dans le sens horaire : + +---- +y/←↑→↓/↑→↓←/ +---- + +Exemple : convertir toutes les lettres en minuscules : + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Exemple : décaler toutes les lettres d'une position, en préservant la casse : +a→b, b→c … y→z, z→a : + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +[[trigger_regex_variable]] +==== Variable + +Si _var_ n'existe pas dans la table de hachage, elle est automatiquement créée +avec une valeur vide. Cela permet de créer des variables temporaires. + +Si _var_ n'est pas spécifiée, la variable par défaut est utilisée, elle dépend +du type de hook : + +[width="100%",cols="2,3,7",options="header"] +|=== +| Hook | Variable par défaut | Mise à jour autorisée ^(1)^ +| signal | tg_signal_data | +| hsignal | | +| modifier | tg_string | tg_string +| line | message | buffer, buffer_name, y, date, date_printed, str_time, tags, notify_level, highlight, prefix, message +| print | tg_message | +| command | tg_argv_eol1 | +| command_run | tg_command | +| timer | tg_remaining_calls | +| config | tg_value | +| focus | | +| info | tg_info | tg_info +| info_hashtable | | toutes les variables reçues dans la table de hachage +|=== + +[NOTE] +^(1)^ Toutes les variables peuvent être mises à jour dans le trigger, mais +seulement ces variables ont un effet sur la valeur retournée par le trigger +et utilisée par WeeChat. + [[trigger_command]] === Commande diff --git a/doc/it/weechat_user.it.adoc b/doc/it/weechat_user.it.adoc index a0b8d5119..a75a68884 100644 --- a/doc/it/weechat_user.it.adoc +++ b/doc/it/weechat_user.it.adoc @@ -5177,42 +5177,47 @@ ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) The regular expression is used to change variables in callback hashtable. -The format is: "/regex/replace" or "/regex/replace/var" (where _var_ is a -variable of the hashtable). +Format is one of the following: -If _var_ does not exist in the hashtable, it is created automatically with an -empty value. This allows to create custom temporary variables. +---- +/string1/string2 +s/string1/string2 +s/string1/string2/var +y/string1/string2 +y/string1/string2/var +---- -If _var_ is not specified, the default variable is used, it depends on hook -type: +Fields: -[width="100%",cols="2,3,7",options="header"] -|=== -| Hook | Default variable | Update allowed ^(1)^ -| signal | tg_signal_data | -| hsignal | | -| modifier | tg_string | tg_string -| line | message | buffer, buffer_name, y, date, date_printed, str_time, tags, notify_level, highlight, prefix, message -| print | tg_message | -| command | tg_argv_eol1 | -| command_run | tg_command | -| timer | tg_remaining_calls | -| config | tg_value | -| focus | | -| info | tg_info | tg_info -| info_hashtable | | all variables received in hashtable -|=== - -[NOTE] -^(1)^ All variables can be updated in the trigger, but only these variables -have an effect on the value returned by the trigger and used by WeeChat. +* `s` or `y`: a letter with the command; if missing, default command is `s` + and the first char is then used as the delimiter: +** `s`: regex replacement: first string is a regular expression, second string + is the replacement for every matching string +** `y`: chars translation: first string is a set of characters that are replaced + by the characters in the second string; once evaluated, each string must have + exactly the same number of UTF-8 chars +* `/`: the regex delimiter; the char "/" can be replaced by any char + (one or more identical chars) +* `string1`: the first string (use depends on the command) +* `string2`: the second string (use depends on the command) +* `var`: the hashtable variable to update Many regular expressions can be separated by a space, for example: -"/regex1/replace1/var1 /regex2/replace2/var2". -The char "/" can be replaced by any char (one or more identical chars). +---- +s/regex1/replace1/var1 y/abcdef/ABDDEF/var2 +---- + +[[trigger_regex_replace]] +==== Regex replace + +For the command `s`, the format is: `s/regex/replace` or `s/regex/replace/var` +(where _var_ is a variable of the hashtable). -Matching groups can be used in "replace": +As `s` is the default command, it can be omitted, so `/regex/replace` is also +valid (but the first char, which is the delimiter, must not be a letter). + +Matching groups can be used in _replace_: * `+${re:0}+` to `+${re:99}+`: `+${re:0}+` is the whole match, `+${re:1}+` to `+${re:99}+` are groups captured @@ -5224,7 +5229,7 @@ Matching groups can be used in "replace": Example: use bold for words between `+*+`: ---- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ---- Example: default trigger _server_pass_ uses this regular expression to hide @@ -5232,13 +5237,73 @@ password in commands `/server` and `/connect` (chars in passwords are replaced by `+*+`): ---- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ---- [NOTE] In this example, the delimiter used is "==" because there is a "/" in the regular expression. +[[trigger_regex_translate_chars]] +==== Translate chars + +For the command `y`, the format is: `y/chars1/chars2` or `y/chars1/chars2/var` +(where _var_ is a variable of the hashtable). + +Example: replace "a", "b" and "c" by upper case letter: + +---- +y/abc/ABC/ +---- + +Example: rotate arrows clockwise: + +---- +y/←↑→↓/↑→↓←/ +---- + +Example: convert all letters to lower case: + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Example: shift each letter by one position, preserving case: a→b, b→c … y→z, z→a: + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +[[trigger_regex_variable]] +==== Variable + +If _var_ does not exist in the hashtable, it is created automatically with an +empty value. This allows to create custom temporary variables. + +If _var_ is not specified, the default variable is used, it depends on hook +type: + +[width="100%",cols="2,3,7",options="header"] +|=== +| Hook | Default variable | Update allowed ^(1)^ +| signal | tg_signal_data | +| hsignal | | +| modifier | tg_string | tg_string +| line | message | buffer, buffer_name, y, date, date_printed, str_time, tags, notify_level, highlight, prefix, message +| print | tg_message | +| command | tg_argv_eol1 | +| command_run | tg_command | +| timer | tg_remaining_calls | +| config | tg_value | +| focus | | +| info | tg_info | tg_info +| info_hashtable | | all variables received in hashtable +|=== + +[NOTE] +^(1)^ All variables can be updated in the trigger, but only these variables +have an effect on the value returned by the trigger and used by WeeChat. + [[trigger_command]] === Command diff --git a/doc/ja/weechat_user.ja.adoc b/doc/ja/weechat_user.ja.adoc index 5494fcc2f..8bd7a5a6c 100644 --- a/doc/ja/weechat_user.ja.adoc +++ b/doc/ja/weechat_user.ja.adoc @@ -4985,19 +4985,120 @@ trigger.trigger.beep.post_action = none ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) ---- +// TRANSLATION MISSING [[trigger_regex]] -=== 正規表現 +=== Regular expression + +The regular expression is used to change variables in callback hashtable. + +Format is one of the following: + +---- +/string1/string2 +s/string1/string2 +s/string1/string2/var +y/string1/string2 +y/string1/string2/var +---- + +Fields: + +* `s` or `y`: a letter with the command; if missing, default command is `s` + and the first char is then used as the delimiter: +** `s`: regex replacement: first string is a regular expression, second string + is the replacement for every matching string +** `y`: chars translation: first string is a set of characters that are replaced + by the characters in the second string; once evaluated, each string must have + exactly the same number of UTF-8 chars +* `/`: the regex delimiter; the char "/" can be replaced by any char + (one or more identical chars) +* `string1`: the first string (use depends on the command) +* `string2`: the second string (use depends on the command) +* `var`: the hashtable variable to update + +Many regular expressions can be separated by a space, for example: + +---- +s/regex1/replace1/var1 y/abcdef/ABDDEF/var2 +---- + +// TRANSLATION MISSING +[[trigger_regex_replace]] +==== Regex replace + +For the command `s`, the format is: `s/regex/replace` or `s/regex/replace/var` +(where _var_ is a variable of the hashtable). + +As `s` is the default command, it can be omitted, so `/regex/replace` is also +valid (but the first char, which is the delimiter, must not be a letter). -正規表現はコールバックハッシュテーブル内の変数を変更するために使われます。 +Matching groups can be used in _replace_: -書式: "/regex/replace" または "/regex/replace/var" (ここで -_var_ はハッシュテーブルの変数)。 +* `+${re:0}+` to `+${re:99}+`: `+${re:0}+` is the whole match, `+${re:1}+` to + `+${re:99}+` are groups captured +* `+${re:+}+`: the last match (with highest number) +* `+${hide:c,${re:N}}+`: match "N" with all chars replaced by "c" + (example: `+${hide:*,${re:2}}+` is the group #2 with all chars replaced by + `+*+`). -ハッシュテーブル内に _var_ が存在しない場合、空の値を持つ _var_ -が自動的に作られます。これを使うことで一時的な任意の変数を作れます。 +Example: use bold for words between `+*+`: -_var_ -が指定されなかった場合、デフォルト変数を使います、これはフックの種類に依存します: +---- +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +---- + +Example: default trigger _server_pass_ uses this regular expression to hide +password in commands `/server` and `/connect` (chars in passwords are replaced +by `+*+`): + +---- +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +---- + +[NOTE] +In this example, the delimiter used is "==" because there is a "/" in the +regular expression. + +// TRANSLATION MISSING +[[trigger_regex_translate_chars]] +==== Translate chars + +For the command `y`, the format is: `y/chars1/chars2` or `y/chars1/chars2/var` +(where _var_ is a variable of the hashtable). + +Example: replace "a", "b" and "c" by upper case letter: + +---- +y/abc/ABC/ +---- + +Example: rotate arrows clockwise: + +---- +y/←↑→↓/↑→↓←/ +---- + +Example: convert all letters to lower case: + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Example: shift each letter by one position, preserving case: a→b, b→c … y→z, z→a: + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +// TRANSLATION MISSING +[[trigger_regex_variable]] +==== Variable + +If _var_ does not exist in the hashtable, it is created automatically with an +empty value. This allows to create custom temporary variables. + +If _var_ is not specified, the default variable is used, it depends on hook +type: [width="100%",cols="2,3,7",options="header"] |=== @@ -5020,38 +5121,6 @@ _var_ ^(1)^ トリガはすべての値を更新できますが、ここで挙げた変数だけがトリガによって返されて WeeChat によって使われる値に影響を及ぼします -複数の正規表現を使う場合は空白で区切ってください、例: -"/regex1/replace1/var1 /regex2/replace2/var2"。 - -文字 "/" を任意の文字 (1 つ以上の同じ文字) に変えることができます。 - -マッチグループを "replace" の中で利用できます: - -* `+${re:0}+` から `+${re:99}+`: `+${re:0}+` はマッチ部分の全体、`+${re:1}+` から - `+${re:99}+` はグループ化されたマッチ部分 -* `+${re:+}+`: 最後のマッチ部分 (最大のグループ番号を持つ) -* `+${hide:c,${re:N}}+`: マッチグループ "N" のすべての文字を "c" で置換した文字列 - (例: `+${hide:*,${re:2}}+` はグループ #2 のすべての文字を `+*+` - で置換した文字列)。 - -例: `+*+` で囲まれた文字を太字にする: - ----- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ----- - -例: デフォルトトリガ _server_pass_ はこの正規表現を使って、`/server` -と `/connect` コマンドのパスワードを隠しています (パスワード部分の文字を -`*` で置換しています): - ----- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ----- - -[NOTE] -この例では、区切り文字として "==" を使っています。これは正規表現内で -"/" を使うためです。 - [[trigger_command]] === コマンド diff --git a/doc/pl/weechat_user.pl.adoc b/doc/pl/weechat_user.pl.adoc index 9abb6e6f6..b7c4899e1 100644 --- a/doc/pl/weechat_user.pl.adoc +++ b/doc/pl/weechat_user.pl.adoc @@ -4904,19 +4904,120 @@ w przypadku podświetlenia lub otrzymania prywatnej wiadomości: ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) ---- +// TRANSLATION MISSING [[trigger_regex]] -=== Wyrażenia regularne +=== Regular expression + +The regular expression is used to change variables in callback hashtable. + +Format is one of the following: + +---- +/string1/string2 +s/string1/string2 +s/string1/string2/var +y/string1/string2 +y/string1/string2/var +---- + +Fields: + +* `s` or `y`: a letter with the command; if missing, default command is `s` + and the first char is then used as the delimiter: +** `s`: regex replacement: first string is a regular expression, second string + is the replacement for every matching string +** `y`: chars translation: first string is a set of characters that are replaced + by the characters in the second string; once evaluated, each string must have + exactly the same number of UTF-8 chars +* `/`: the regex delimiter; the char "/" can be replaced by any char + (one or more identical chars) +* `string1`: the first string (use depends on the command) +* `string2`: the second string (use depends on the command) +* `var`: the hashtable variable to update + +Many regular expressions can be separated by a space, for example: + +---- +s/regex1/replace1/var1 y/abcdef/ABDDEF/var2 +---- + +// TRANSLATION MISSING +[[trigger_regex_replace]] +==== Regex replace + +For the command `s`, the format is: `s/regex/replace` or `s/regex/replace/var` +(where _var_ is a variable of the hashtable). + +As `s` is the default command, it can be omitted, so `/regex/replace` is also +valid (but the first char, which is the delimiter, must not be a letter). -Wyrażenia regularne są używane do zmiany zmiennych w tablicy hashy callbacka. +Matching groups can be used in _replace_: -Format: "/wyrażenie/zamień" lub "/wyrażenie/zamień/zmienna" (gdzie _zmienna_ to -zmienna tablicy hashy). +* `+${re:0}+` to `+${re:99}+`: `+${re:0}+` is the whole match, `+${re:1}+` to + `+${re:99}+` are groups captured +* `+${re:+}+`: the last match (with highest number) +* `+${hide:c,${re:N}}+`: match "N" with all chars replaced by "c" + (example: `+${hide:*,${re:2}}+` is the group #2 with all chars replaced by + `+*+`). -Jeśli _zmienna_ nie istnieje w tablicy haszy zostanie automarycznie utworzona bez -wartości. Pozwala to tworzyć dowolne zmienne tymczasowe. +Example: use bold for words between `+*+`: -Jeśli _zmienna_ nie zostanie podana, użyta zostanie domyślna zmienna, zależy ona -od typu uchwytu: +---- +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +---- + +Example: default trigger _server_pass_ uses this regular expression to hide +password in commands `/server` and `/connect` (chars in passwords are replaced +by `+*+`): + +---- +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +---- + +[NOTE] +In this example, the delimiter used is "==" because there is a "/" in the +regular expression. + +// TRANSLATION MISSING +[[trigger_regex_translate_chars]] +==== Translate chars + +For the command `y`, the format is: `y/chars1/chars2` or `y/chars1/chars2/var` +(where _var_ is a variable of the hashtable). + +Example: replace "a", "b" and "c" by upper case letter: + +---- +y/abc/ABC/ +---- + +Example: rotate arrows clockwise: + +---- +y/←↑→↓/↑→↓←/ +---- + +Example: convert all letters to lower case: + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Example: shift each letter by one position, preserving case: a→b, b→c … y→z, z→a: + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +// TRANSLATION MISSING +[[trigger_regex_variable]] +==== Variable + +If _var_ does not exist in the hashtable, it is created automatically with an +empty value. This allows to create custom temporary variables. + +If _var_ is not specified, the default variable is used, it depends on hook +type: [width="100%",cols="2,3,7",options="header"] |=== @@ -4939,36 +5040,6 @@ od typu uchwytu: ^(1)^ Wszystkie zmienne mogą zostać zaktualizowane, jednak tylko te zmienne mają wpływ na zmienne zwrócone i użyte przez WeeChat. -Wiele wyrażeń może być oddzielonych spacją, na przykład: -"/regex1/zamień1/zmienna1 /regex2/zamień2/zmienna2". - -Znak "/" może zostać zastąpiony dowolnym znakiem (jednym lub kilkoma -identycznymi znakami). - -Dopasowane grupy, które mogą zostać użyte w "zamień": - -* `+${re:0}+` to `+${re:99}+`: `+${re:0}+` to pełne dopasowanie, `+${re:1}+` do - `+${re:99}+` to przechwycone grupy -* `+${re:+}+`: ostatnie dopasowanie (z najwyższym numerem) -* `+${hide:c,${re:N}}+`: dopasowanie "N" z wszystkimi znakami zastąpionymi "c" - (przykład: `+${hide:*,${re:2}}+` to grupa #2 ze znakami zastąpionymi `+*+`). - -Przykład: użyj pogrubienia dla słów pomiędzy `+*+`: - ----- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ----- - -Przykład: domyślny trigger _server_pass_ używa tego wyrażenia do ukrycia hasła -w komendach `/server` i `/connect` (znaki haseł są zastępowane przez `+*+`): - ----- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ----- - -[NOTE] -W tym przykładzie, użyty jest separator "==" ponieważ w wyrażeniu występuje "/". - [[trigger_command]] === Komenda diff --git a/doc/sr/weechat_user.sr.adoc b/doc/sr/weechat_user.sr.adoc index 0e72af7a5..4f2c8c72e 100644 --- a/doc/sr/weechat_user.sr.adoc +++ b/doc/sr/weechat_user.sr.adoc @@ -4559,16 +4559,120 @@ link:weechat_plugin_api.sr.html#_hook_info[hook_info ^↗^,window=_blank] ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) ---- +// TRANSLATION MISSING [[trigger_regex]] -=== Регуларни израз +=== Regular expression + +The regular expression is used to change variables in callback hashtable. + +Format is one of the following: + +---- +/string1/string2 +s/string1/string2 +s/string1/string2/var +y/string1/string2 +y/string1/string2/var +---- + +Fields: + +* `s` or `y`: a letter with the command; if missing, default command is `s` + and the first char is then used as the delimiter: +** `s`: regex replacement: first string is a regular expression, second string + is the replacement for every matching string +** `y`: chars translation: first string is a set of characters that are replaced + by the characters in the second string; once evaluated, each string must have + exactly the same number of UTF-8 chars +* `/`: the regex delimiter; the char "/" can be replaced by any char + (one or more identical chars) +* `string1`: the first string (use depends on the command) +* `string2`: the second string (use depends on the command) +* `var`: the hashtable variable to update + +Many regular expressions can be separated by a space, for example: + +---- +s/regex1/replace1/var1 y/abcdef/ABDDEF/var2 +---- + +// TRANSLATION MISSING +[[trigger_regex_replace]] +==== Regex replace + +For the command `s`, the format is: `s/regex/replace` or `s/regex/replace/var` +(where _var_ is a variable of the hashtable). + +As `s` is the default command, it can be omitted, so `/regex/replace` is also +valid (but the first char, which is the delimiter, must not be a letter). -Регуларни израз се користи за измену променљивих у хеш табели функције повратног позива. +Matching groups can be used in _replace_: -Формат је следећи: „/регизраз/замена” или „/регизраз/замена/пром” (где је _пром_ променљива хеш табеле). +* `+${re:0}+` to `+${re:99}+`: `+${re:0}+` is the whole match, `+${re:1}+` to + `+${re:99}+` are groups captured +* `+${re:+}+`: the last match (with highest number) +* `+${hide:c,${re:N}}+`: match "N" with all chars replaced by "c" + (example: `+${hide:*,${re:2}}+` is the group #2 with all chars replaced by + `+*+`). -Ако _пром_ не постоји у хеш табели, она се аутоматски креира и има празну вредност. На овај начин могу да се креирају произвољне привремене променљиве. +Example: use bold for words between `+*+`: -Ако се _пром_ не наведе, користи се подразумевана променљива која зависи од типа употребљене куке: +---- +s/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ +---- + +Example: default trigger _server_pass_ uses this regular expression to hide +password in commands `/server` and `/connect` (chars in passwords are replaced +by `+*+`): + +---- +s==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} +---- + +[NOTE] +In this example, the delimiter used is "==" because there is a "/" in the +regular expression. + +// TRANSLATION MISSING +[[trigger_regex_translate_chars]] +==== Translate chars + +For the command `y`, the format is: `y/chars1/chars2` or `y/chars1/chars2/var` +(where _var_ is a variable of the hashtable). + +Example: replace "a", "b" and "c" by upper case letter: + +---- +y/abc/ABC/ +---- + +Example: rotate arrows clockwise: + +---- +y/←↑→↓/↑→↓←/ +---- + +Example: convert all letters to lower case: + +---- +y/${chars:upper}/${chars:lower}/ +---- + +Example: shift each letter by one position, preserving case: a→b, b→c … y→z, z→a: + +---- +y/${chars:a-z}${chars:A-Z}/${chars:b-z}a${chars:B-Z}A/ +---- + +// TRANSLATION MISSING +[[trigger_regex_variable]] +==== Variable + +If _var_ does not exist in the hashtable, it is created automatically with an +empty value. This allows to create custom temporary variables. + +If _var_ is not specified, the default variable is used, it depends on hook +type: [width="100%", cols="2,3,7", options="header"] |=== @@ -4590,31 +4694,6 @@ ${tg_displayed} && (${tg_highlight} || ${tg_msg_pv}) [NOTE] ^(1)^ У окидачу је могуће ажурирање свих променљивих, али само ове променљиве утичу на вредност коју враћа окидач и коју користи програм WeeChat. -Више регуларних израза може да се раздвоји размаком, на пример: /регизраз1/замена1/пром1 /регизраз2/замена2/пром2". - -Карактер „/” може да се замени било којим карактером (један или више идентичних карактера). - -У „замена” могу да се користе групе подударања: - -* `+${re:0}+` до `+${re:99}+`: `+${re:0}+` је комплетно подударање, `+${re:1}+` до `+${re:99}+` су ухваћене групе -* `+${re:+}+`: последње подударање (са највишим бројем) -* `+${hide:c,${re:N}}+`: подударање „N” са свим карактерима се замењује са „c” (пример: `+${hide:*,${re:2}}+` је група #2 у којој су сви карактери замењени са `+*+`). - -Пример: користи подебљан текст за речи уоквирене са `+*+`: - ----- -/\*([^ ]+)\*/*${color:bold}${re:1}${color:-bold}*/ ----- - -Пример: подразумевани окидач _server_pass_ користи следећи регуларни израз да сакрије лозинке у командама `/server` и `/connect` (карактери у лозинкама се замењују са `+*+`): - ----- -==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==${re:1}${hide:*,${re:4}}${re:5} ----- - -[NOTE] -У овом примеру се користи „==” као граничник јер у регуларном изразу постоји „/”. - [[trigger_command]] === Команда diff --git a/src/plugins/trigger/trigger-callback.c b/src/plugins/trigger/trigger-callback.c index 2f1d7cf69..fab098fb1 100644 --- a/src/plugins/trigger/trigger-callback.c +++ b/src/plugins/trigger/trigger-callback.c @@ -267,18 +267,95 @@ trigger_callback_check_conditions (struct t_trigger *trigger, } /* - * Replaces text using one or more regex in the trigger. + * Replaces text using regex. + * + * Returns: text replaced. + * + * Note: result must be freed after use. + */ + +char * +trigger_callback_regex_replace (struct t_trigger_context *context, + const char *text, + regex_t *regex, + const char *replace) +{ + char *value; + struct t_hashtable *hashtable_options_regex; + + if (!regex) + return NULL; + + hashtable_options_regex = weechat_hashtable_new ( + 32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, NULL); + + weechat_hashtable_set (context->pointers, "regex", regex); + weechat_hashtable_set (hashtable_options_regex, + "regex_replace", replace); + + value = weechat_string_eval_expression ( + text, + context->pointers, + context->extra_vars, + hashtable_options_regex); + + weechat_hashtable_free (hashtable_options_regex); + + return value; +} + +/* + * Translates chars. + * + * Returns: text with translated chars. + * + * Note: result must be freed after use. + */ + +char * +trigger_callback_regex_translate_chars (struct t_trigger_context *context, + const char *text, + const char *chars1, + const char *chars2) +{ + char *value, *chars1_eval, *chars2_eval; + + chars1_eval = weechat_string_eval_expression ( + chars1, + context->pointers, + context->extra_vars, + NULL); + chars2_eval = weechat_string_eval_expression ( + chars2, + context->pointers, + context->extra_vars, + NULL); + + value = weechat_string_translate_chars (text, chars1_eval, chars2_eval); + + if (chars1_eval) + free (chars1_eval); + if (chars2_eval) + free (chars2_eval); + + return value; +} + +/* + * Executes regex commands. */ void -trigger_callback_replace_regex (struct t_trigger *trigger, - struct t_trigger_context *context, - int display_monitor) +trigger_callback_regex (struct t_trigger *trigger, + struct t_trigger_context *context, + int display_monitor) { char *value; const char *ptr_key, *ptr_value; int i, pointers_allocated; - struct t_hashtable *hashtable_options_regex; pointers_allocated = 0; @@ -298,9 +375,12 @@ trigger_callback_replace_regex (struct t_trigger *trigger, for (i = 0; i < trigger->regex_count; i++) { - /* if regex is not set (invalid), skip it */ - if (!trigger->regex[i].regex) + /* if regex is not set (invalid) for command "regex replace", skip it */ + if ((trigger->regex[i].command == TRIGGER_REGEX_COMMAND_REPLACE) + && !trigger->regex[i].regex) + { continue; + } ptr_key = (trigger->regex[i].variable) ? trigger->regex[i].variable : @@ -336,25 +416,25 @@ trigger_callback_replace_regex (struct t_trigger *trigger, ptr_value = weechat_hashtable_get (context->extra_vars, ptr_key); } - hashtable_options_regex = weechat_hashtable_new ( - 32, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, NULL); - - weechat_hashtable_set (context->pointers, - "regex", trigger->regex[i].regex); - weechat_hashtable_set (hashtable_options_regex, - "regex_replace", - trigger->regex[i].replace_escaped); - - value = weechat_string_eval_expression ( - ptr_value, - context->pointers, - context->extra_vars, - hashtable_options_regex); - - weechat_hashtable_free (hashtable_options_regex); + switch (trigger->regex[i].command) + { + case TRIGGER_REGEX_COMMAND_REPLACE: + value = trigger_callback_regex_replace ( + context, + ptr_value, + trigger->regex[i].regex, + trigger->regex[i].replace_escaped); + break; + case TRIGGER_REGEX_COMMAND_TRANSLATE_CHARS: + value = trigger_callback_regex_translate_chars ( + context, + ptr_value, + trigger->regex[i].str_regex, + trigger->regex[i].replace); + break; + case TRIGGER_NUM_REGEX_COMMANDS: + break; + } if (value) { @@ -493,7 +573,7 @@ trigger_callback_execute (struct t_trigger *trigger, if (weechat_trigger_plugin->debug >= 1) { gettimeofday (&(context->start_check_conditions), NULL); - context->start_replace_regex = context->start_check_conditions; + context->start_regex = context->start_check_conditions; context->start_run_command = context->start_check_conditions; } @@ -505,7 +585,7 @@ trigger_callback_execute (struct t_trigger *trigger, /* replace text with regex */ if (weechat_trigger_plugin->debug >= 1) gettimeofday (&(context->start_check_conditions), NULL); - trigger_callback_replace_regex (trigger, context, display_monitor); + trigger_callback_regex (trigger, context, display_monitor); /* execute command(s) */ if (weechat_trigger_plugin->debug >= 1) @@ -524,8 +604,8 @@ trigger_callback_execute (struct t_trigger *trigger, time_init = weechat_util_timeval_diff (&(context->start_exec), &(context->start_check_conditions)); time_cond = weechat_util_timeval_diff (&(context->start_check_conditions), - &(context->start_replace_regex)); - time_regex = weechat_util_timeval_diff (&(context->start_replace_regex), + &(context->start_regex)); + time_regex = weechat_util_timeval_diff (&(context->start_regex), &(context->start_run_command)); time_cmd = weechat_util_timeval_diff (&(context->start_run_command), &(context->end_exec)); diff --git a/src/plugins/trigger/trigger-callback.h b/src/plugins/trigger/trigger-callback.h index 07da9b0bb..7435129fc 100644 --- a/src/plugins/trigger/trigger-callback.h +++ b/src/plugins/trigger/trigger-callback.h @@ -32,7 +32,7 @@ struct t_trigger_context struct t_weelist *vars_updated; struct timeval start_exec; struct timeval start_check_conditions; - struct timeval start_replace_regex; + struct timeval start_regex; struct timeval start_run_command; struct timeval end_exec; }; diff --git a/src/plugins/trigger/trigger.c b/src/plugins/trigger/trigger.c index af2ad0c4e..43518c291 100644 --- a/src/plugins/trigger/trigger.c +++ b/src/plugins/trigger/trigger.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <ctype.h> #include <regex.h> #include "../weechat-plugin.h" @@ -61,6 +62,8 @@ char *trigger_hook_default_rc[TRIGGER_NUM_HOOK_TYPES] = { "ok,ok_eat,error", "ok,ok_eat,error", "", "", "ok,error", "ok,error", "ok,ok_eat,error", "ok", "ok", "", "", "" }; +char trigger_regex_command[TRIGGER_NUM_REGEX_COMMANDS] = +{ 's', 'y' }; char *trigger_hook_regex_default_var[TRIGGER_NUM_HOOK_TYPES] = { "tg_signal_data", "", "tg_string", "message", "tg_message", "tg_argv_eol1", "tg_command", "tg_remaining_calls", "tg_value", "", "tg_info", "" }; @@ -129,6 +132,27 @@ trigger_search_hook_type (const char *type) } /* + * Searches for a regex command. + * + * Returns index of option in enum t_trigger_regex_command, -1 if not found. + */ + +int +trigger_search_regex_command (char command) +{ + int i; + + for (i = 0; i < TRIGGER_NUM_REGEX_COMMANDS; i++) + { + if (trigger_regex_command[i] == command) + return i; + } + + /* regex command not found */ + return -1; +} + +/* * Searches for trigger return code. * * Returns index of return code in enum t_trigger_return_code, -1 if not found. @@ -630,7 +654,7 @@ trigger_regex_split (const char *str_regex, const char *ptr_regex, *pos, *pos_replace, *pos_replace_end; const char *pos_next_regex; char *delimiter, *str_regex_escaped; - int rc, index, length_delimiter; + int rc, index, length_delimiter, command; struct t_trigger_regex *new_regex; rc = 0; @@ -660,6 +684,21 @@ trigger_regex_split (const char *str_regex, delimiter = NULL; } + /* extract command */ + if (isalpha ((unsigned char)ptr_regex[0])) + { + command = trigger_search_regex_command (ptr_regex[0]); + if (command < 0) + goto format_error; + /* skip the command */ + ptr_regex = weechat_utf8_next_char (ptr_regex); + } + else + { + /* default command is "s" (replace regex) */ + command = TRIGGER_REGEX_COMMAND_REPLACE; + } + /* search the delimiter (which can be more than one char) */ pos = weechat_utf8_next_char (ptr_regex); while (pos[0] && (weechat_utf8_charcmp (ptr_regex, pos) == 0)) @@ -694,6 +733,7 @@ trigger_regex_split (const char *str_regex, index = *regex_count - 1; /* initialize new regex */ + (*regex)[index].command = command; (*regex)[index].variable = NULL; (*regex)[index].str_regex = NULL; (*regex)[index].regex = NULL; @@ -705,36 +745,44 @@ trigger_regex_split (const char *str_regex, pos_replace - ptr_regex); if (!(*regex)[index].str_regex) goto memory_error; - if (str_regex_escaped) - free (str_regex_escaped); - str_regex_escaped = weechat_string_convert_escaped_chars ((*regex)[index].str_regex); - if (!str_regex_escaped) - goto memory_error; - /* set regex */ - (*regex)[index].regex = malloc (sizeof (*(*regex)[index].regex)); - if (!(*regex)[index].regex) - goto memory_error; - if (weechat_string_regcomp ((*regex)[index].regex, - str_regex_escaped, - REG_EXTENDED | REG_ICASE) != 0) + /* set regex (command "s" only) */ + if (command == TRIGGER_REGEX_COMMAND_REPLACE) { - free ((*regex)[index].regex); - (*regex)[index].regex = NULL; - goto compile_error; + if (str_regex_escaped) + free (str_regex_escaped); + str_regex_escaped = weechat_string_convert_escaped_chars ((*regex)[index].str_regex); + if (!str_regex_escaped) + goto memory_error; + (*regex)[index].regex = malloc (sizeof (*(*regex)[index].regex)); + if (!(*regex)[index].regex) + goto memory_error; + if (weechat_string_regcomp ((*regex)[index].regex, + str_regex_escaped, + REG_EXTENDED | REG_ICASE) != 0) + { + free ((*regex)[index].regex); + (*regex)[index].regex = NULL; + goto compile_error; + } } - /* set replace and replace_eval */ + /* set replace */ (*regex)[index].replace = (pos_replace_end) ? weechat_strndup (pos_replace + length_delimiter, pos_replace_end - pos_replace - length_delimiter) : strdup (pos_replace + length_delimiter); if (!(*regex)[index].replace) goto memory_error; - (*regex)[index].replace_escaped = - weechat_string_convert_escaped_chars ((*regex)[index].replace); - if (!(*regex)[index].replace_escaped) - goto memory_error; + + /* set replace_escaped (command "s" only) */ + if (command == TRIGGER_REGEX_COMMAND_REPLACE) + { + (*regex)[index].replace_escaped = + weechat_string_convert_escaped_chars ((*regex)[index].replace); + if (!(*regex)[index].replace_escaped) + goto memory_error; + } if (!pos_replace_end) break; diff --git a/src/plugins/trigger/trigger.h b/src/plugins/trigger/trigger.h index 2807b3f06..7641a398d 100644 --- a/src/plugins/trigger/trigger.h +++ b/src/plugins/trigger/trigger.h @@ -79,8 +79,17 @@ enum t_trigger_post_action TRIGGER_NUM_POST_ACTIONS, }; +enum t_trigger_regex_command +{ + TRIGGER_REGEX_COMMAND_REPLACE = 0, + TRIGGER_REGEX_COMMAND_TRANSLATE_CHARS, + /* number of regex commands */ + TRIGGER_NUM_REGEX_COMMANDS, +}; + struct t_trigger_regex { + enum t_trigger_regex_command command; /* regex command */ char *variable; /* the hashtable key used */ char *str_regex; /* regex to search for replacement */ regex_t *regex; /* compiled regex */ @@ -104,7 +113,7 @@ struct t_trigger int hook_running; /* 1 if one hook callback is running */ char *hook_print_buffers; /* buffers (for hook_print only) */ - /* regular expressions with their replacement text */ + /* regular expressions */ int regex_count; /* number of regex */ struct t_trigger_regex *regex; /* array of regex */ @@ -124,6 +133,7 @@ extern char *trigger_hook_type_string[]; extern char *trigger_hook_option_values; extern char *trigger_hook_default_arguments[]; extern char *trigger_hook_default_rc[]; +extern char trigger_regex_command[]; extern char *trigger_hook_regex_default_var[]; extern char *trigger_return_code_string[]; extern int trigger_return_code[]; @@ -137,6 +147,7 @@ extern int trigger_enabled; extern int trigger_search_option (const char *option_name); extern int trigger_search_hook_type (const char *type); +extern int trigger_search_regex_command (char command); extern int trigger_search_return_code (const char *return_code); extern int trigger_search_post_action (const char *post_action); extern struct t_trigger *trigger_search (const char *name); diff --git a/tests/unit/plugins/trigger/test-trigger.cpp b/tests/unit/plugins/trigger/test-trigger.cpp index 12617d43c..c919792f4 100644 --- a/tests/unit/plugins/trigger/test-trigger.cpp +++ b/tests/unit/plugins/trigger/test-trigger.cpp @@ -93,6 +93,28 @@ TEST(Trigger, SearchHookType) /* * Tests functions: + * trigger_search_regex_command + */ + +TEST(Trigger, SearchRegexCommand) +{ + int i; + + LONGS_EQUAL(-1, trigger_search_regex_command ('a')); + LONGS_EQUAL(-1, trigger_search_regex_command ('z')); + LONGS_EQUAL(-1, trigger_search_regex_command ('/')); + LONGS_EQUAL(-1, trigger_search_regex_command ('*')); + LONGS_EQUAL(-1, trigger_search_regex_command (' ')); + + for (i = 0; i < TRIGGER_NUM_REGEX_COMMANDS; i++) + { + LONGS_EQUAL(i, + trigger_search_regex_command (trigger_regex_command[i])); + } +} + +/* + * Tests functions: * trigger_search_return_code */ @@ -179,20 +201,34 @@ TEST(Trigger, RegexSplit) WEE_CHECK_REGEX_SPLIT(0, 0, NULL); WEE_CHECK_REGEX_SPLIT(0, 0, ""); - /* regex too short */ + /* regex too short (default command "s") */ WEE_CHECK_REGEX_SPLIT(-1, 0, "/"); WEE_CHECK_REGEX_SPLIT(-1, 0, "/a"); - /* nothing after the delimiter */ - WEE_CHECK_REGEX_SPLIT(-1, 0, "///"); + /* regex too short with command "s" (regex replace) */ + WEE_CHECK_REGEX_SPLIT(-1, 0, "s/"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "s///"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "s/a"); + + /* regex too short with command "y" (translate chars) */ + WEE_CHECK_REGEX_SPLIT(-1, 0, "y/"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "y///"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "y/a"); /* missing second delimiter */ WEE_CHECK_REGEX_SPLIT(-1, 0, "/abc"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "s/abc"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "y/abc"); + + /* invalid command */ + WEE_CHECK_REGEX_SPLIT(-1, 0, "a/a/b"); + WEE_CHECK_REGEX_SPLIT(-1, 0, "z/a/b"); /* invalid regex */ WEE_CHECK_REGEX_SPLIT(-2, 0, "/*/a"); + WEE_CHECK_REGEX_SPLIT(-2, 0, "s/*/a"); - /* simple regex */ + /* simple regex (implicit command "s") */ WEE_CHECK_REGEX_SPLIT(0, 1, "/a/b"); POINTERS_EQUAL(NULL, regex[0].variable); STRCMP_EQUAL("a", regex[0].str_regex); @@ -200,7 +236,23 @@ TEST(Trigger, RegexSplit) STRCMP_EQUAL("b", regex[0].replace); STRCMP_EQUAL("b", regex[0].replace_escaped); - /* simple regex with variable */ + /* simple regex replace (command "s") */ + WEE_CHECK_REGEX_SPLIT(0, 1, "s/a/b"); + POINTERS_EQUAL(NULL, regex[0].variable); + STRCMP_EQUAL("a", regex[0].str_regex); + CHECK(regex[0].regex); + STRCMP_EQUAL("b", regex[0].replace); + STRCMP_EQUAL("b", regex[0].replace_escaped); + + /* simple translate chars (command "y") */ + WEE_CHECK_REGEX_SPLIT(0, 1, "y/${chars:a-h}/${chars:A-H}"); + POINTERS_EQUAL(NULL, regex[0].variable); + STRCMP_EQUAL("${chars:a-h}", regex[0].str_regex); + POINTERS_EQUAL(NULL, regex[0].regex); + STRCMP_EQUAL("${chars:A-H}", regex[0].replace); + POINTERS_EQUAL(NULL, regex[0].replace_escaped); + + /* simple regex replace with variable (implicit command "s") */ WEE_CHECK_REGEX_SPLIT(0, 1, "/a/b/var"); STRCMP_EQUAL("var", regex[0].variable); STRCMP_EQUAL("a", regex[0].str_regex); @@ -208,7 +260,23 @@ TEST(Trigger, RegexSplit) STRCMP_EQUAL("b", regex[0].replace); STRCMP_EQUAL("b", regex[0].replace_escaped); - /* 2 regex separated by 3 spaces, without variables */ + /* simple regex replace with variable (command "s") */ + WEE_CHECK_REGEX_SPLIT(0, 1, "s/a/b/var"); + STRCMP_EQUAL("var", regex[0].variable); + STRCMP_EQUAL("a", regex[0].str_regex); + CHECK(regex[0].regex); + STRCMP_EQUAL("b", regex[0].replace); + STRCMP_EQUAL("b", regex[0].replace_escaped); + + /* simple translate chars with variable (command "y") */ + WEE_CHECK_REGEX_SPLIT(0, 1, "y/${chars:a-h}/${chars:A-H}/var"); + STRCMP_EQUAL("var", regex[0].variable); + STRCMP_EQUAL("${chars:a-h}", regex[0].str_regex); + POINTERS_EQUAL(NULL, regex[0].regex); + STRCMP_EQUAL("${chars:A-H}", regex[0].replace); + POINTERS_EQUAL(NULL, regex[0].replace_escaped); + + /* 2 regex replace separated by 3 spaces, without variables, implicit command "s" */ WEE_CHECK_REGEX_SPLIT(0, 2, "/abc/def/ /ghi/jkl/"); POINTERS_EQUAL(NULL, regex[0].variable); STRCMP_EQUAL("abc", regex[0].str_regex); @@ -221,7 +289,33 @@ TEST(Trigger, RegexSplit) STRCMP_EQUAL("jkl", regex[1].replace); STRCMP_EQUAL("jkl", regex[1].replace_escaped); - /* 3 regex with variables and escaped replace */ + /* 2 regex replace separated by 3 spaces, without variables, command "s" */ + WEE_CHECK_REGEX_SPLIT(0, 2, "s/abc/def/ s/ghi/jkl/"); + POINTERS_EQUAL(NULL, regex[0].variable); + STRCMP_EQUAL("abc", regex[0].str_regex); + CHECK(regex[0].regex); + STRCMP_EQUAL("def", regex[0].replace); + STRCMP_EQUAL("def", regex[0].replace_escaped); + POINTERS_EQUAL(NULL, regex[1].variable); + STRCMP_EQUAL("ghi", regex[1].str_regex); + CHECK(regex[1].regex); + STRCMP_EQUAL("jkl", regex[1].replace); + STRCMP_EQUAL("jkl", regex[1].replace_escaped); + + /* 2 translate chars separated by 3 spaces, without variables, command "y" */ + WEE_CHECK_REGEX_SPLIT(0, 2, "y/abc/ABC/ y/ghi/GHI/"); + POINTERS_EQUAL(NULL, regex[0].variable); + STRCMP_EQUAL("abc", regex[0].str_regex); + POINTERS_EQUAL(NULL, regex[0].regex); + STRCMP_EQUAL("ABC", regex[0].replace); + POINTERS_EQUAL(NULL, regex[0].replace_escaped); + POINTERS_EQUAL(NULL, regex[1].variable); + STRCMP_EQUAL("ghi", regex[1].str_regex); + POINTERS_EQUAL(NULL, regex[1].regex); + STRCMP_EQUAL("GHI", regex[1].replace); + POINTERS_EQUAL(NULL, regex[1].replace_escaped); + + /* 3 regex replace with variables and escaped replace, implicit command "s" */ WEE_CHECK_REGEX_SPLIT(0, 3, "/abc/def/var1 /ghi/jkl/var2 /mno/pqr\\x20stu/var3"); STRCMP_EQUAL("var1", regex[0].variable); @@ -240,6 +334,58 @@ TEST(Trigger, RegexSplit) STRCMP_EQUAL("pqr\\x20stu", regex[2].replace); STRCMP_EQUAL("pqr stu", regex[2].replace_escaped); + /* 3 regex replace with variables and escaped replace, command "s" */ + WEE_CHECK_REGEX_SPLIT( + 0, 3, + "s/abc/def/var1 s/ghi/jkl/var2 s/mno/pqr\\x20stu/var3"); + STRCMP_EQUAL("var1", regex[0].variable); + STRCMP_EQUAL("abc", regex[0].str_regex); + CHECK(regex[0].regex); + STRCMP_EQUAL("def", regex[0].replace); + STRCMP_EQUAL("def", regex[0].replace_escaped); + STRCMP_EQUAL("var2", regex[1].variable); + STRCMP_EQUAL("ghi", regex[1].str_regex); + CHECK(regex[1].regex); + STRCMP_EQUAL("jkl", regex[1].replace); + STRCMP_EQUAL("jkl", regex[1].replace_escaped); + STRCMP_EQUAL("var3", regex[2].variable); + STRCMP_EQUAL("mno", regex[2].str_regex); + CHECK(regex[2].regex); + STRCMP_EQUAL("pqr\\x20stu", regex[2].replace); + STRCMP_EQUAL("pqr stu", regex[2].replace_escaped); + + /* 3 translate chars with variables, command "y" */ + WEE_CHECK_REGEX_SPLIT(0, 3, "y/abc/ABC/var1 y/ghi/GHI/var2 y/mno/MNO/var3"); + STRCMP_EQUAL("var1", regex[0].variable); + STRCMP_EQUAL("abc", regex[0].str_regex); + POINTERS_EQUAL(NULL, regex[0].regex); + STRCMP_EQUAL("ABC", regex[0].replace); + POINTERS_EQUAL(NULL, regex[0].replace_escaped); + STRCMP_EQUAL("var2", regex[1].variable); + STRCMP_EQUAL("ghi", regex[1].str_regex); + POINTERS_EQUAL(NULL, regex[1].regex); + STRCMP_EQUAL("GHI", regex[1].replace); + POINTERS_EQUAL(NULL, regex[1].replace_escaped); + STRCMP_EQUAL("var3", regex[2].variable); + STRCMP_EQUAL("mno", regex[2].str_regex); + POINTERS_EQUAL(NULL, regex[2].regex); + STRCMP_EQUAL("MNO", regex[2].replace); + POINTERS_EQUAL(NULL, regex[2].replace_escaped); + + /* mixed regex replace and translate chars */ + WEE_CHECK_REGEX_SPLIT(0, 2, + "s/abc/defghi/var1 y/${chars:x-z}/${chars:X-Z}/var2"); + STRCMP_EQUAL("var1", regex[0].variable); + STRCMP_EQUAL("abc", regex[0].str_regex); + CHECK(regex[0].regex); + STRCMP_EQUAL("defghi", regex[0].replace); + STRCMP_EQUAL("defghi", regex[0].replace_escaped); + STRCMP_EQUAL("var2", regex[1].variable); + STRCMP_EQUAL("${chars:x-z}", regex[1].str_regex); + POINTERS_EQUAL(NULL, regex[1].regex); + STRCMP_EQUAL("${chars:X-Z}", regex[1].replace); + POINTERS_EQUAL(NULL, regex[1].replace_escaped); + trigger_regex_free (®ex_count, ®ex); } |