diff --git a/CHANGELOG.md b/CHANGELOG.md index eac7a191a..2f7a0991c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ SPDX-License-Identifier: GPL-3.0-or-later ### Added -- core: add `/theme` command with subcommands `list`, `apply`, `save`, `delete`, `info`, automatic backup of current themable options before apply, and built-in "light" theme +- core: add `/theme` command with subcommands `list`, `apply`, `reset`, `save`, `delete`, `info`, automatic backup of current themable options before apply, and built-in "light" theme - core: add `themable` flag on configuration options (auto-set for color options; explicit opt-in for string options containing `${color:...}` references via the `type|themable` syntax) - core: add option weechat.look.theme (informational, set by `/theme apply`) - core: add option weechat.look.theme_backup (boolean, default `on`) diff --git a/doc/de/weechat_user.de.adoc b/doc/de/weechat_user.de.adoc index 434db8f9c..369d4decf 100644 --- a/doc/de/weechat_user.de.adoc +++ b/doc/de/weechat_user.de.adoc @@ -2248,6 +2248,20 @@ is aborted before any option is changed. The name of the last applied theme is stored in `+weechat.look.theme+` (informational only; not re-applied at startup). +[[themes_reset]] +==== Resetting to defaults + +To restore the look shipped with WeeChat, reset every themable option +to its default value: + +---- +/theme reset +---- + +A backup is written first (same gate as `+/theme apply+`); on backup +failure the reset is aborted before any option is changed. +`+weechat.look.theme+` is cleared too. + [[themes_save_delete]] ==== Saving and deleting user themes diff --git a/doc/en/weechat_user.en.adoc b/doc/en/weechat_user.en.adoc index 407800c22..a623d7560 100644 --- a/doc/en/weechat_user.en.adoc +++ b/doc/en/weechat_user.en.adoc @@ -2235,6 +2235,20 @@ is aborted before any option is changed. The name of the last applied theme is stored in `+weechat.look.theme+` (informational only; not re-applied at startup). +[[themes_reset]] +==== Resetting to defaults + +To restore the look shipped with WeeChat, reset every themable option +to its default value: + +---- +/theme reset +---- + +A backup is written first (same gate as `+/theme apply+`); on backup +failure the reset is aborted before any option is changed. +`+weechat.look.theme+` is cleared too. + [[themes_save_delete]] ==== Saving and deleting user themes diff --git a/doc/fr/weechat_user.fr.adoc b/doc/fr/weechat_user.fr.adoc index c38c29948..266e0a1ae 100644 --- a/doc/fr/weechat_user.fr.adoc +++ b/doc/fr/weechat_user.fr.adoc @@ -2282,6 +2282,21 @@ Le nom du dernier thème appliqué est conservé dans `+weechat.look.theme+` (à titre informatif uniquement ; il n'est pas ré-appliqué au démarrage). +[[themes_reset]] +==== Réinitialiser aux valeurs par défaut + +Pour rétablir l'apparence d'origine livrée avec WeeChat, réinitialiser +toutes les options modifiables à leur valeur par défaut : + +---- +/theme reset +---- + +Une sauvegarde est écrite au préalable (même garde-fou que +`+/theme apply+`) ; si la sauvegarde échoue, la réinitialisation est +annulée avant qu'aucune option ne soit modifiée. L'option +`+weechat.look.theme+` est également remise à vide. + [[themes_save_delete]] ==== Sauvegarder et supprimer des thèmes utilisateur diff --git a/doc/it/weechat_user.it.adoc b/doc/it/weechat_user.it.adoc index 4e372000a..b6ccde67e 100644 --- a/doc/it/weechat_user.it.adoc +++ b/doc/it/weechat_user.it.adoc @@ -2490,6 +2490,20 @@ is aborted before any option is changed. The name of the last applied theme is stored in `+weechat.look.theme+` (informational only; not re-applied at startup). +[[themes_reset]] +==== Resetting to defaults + +To restore the look shipped with WeeChat, reset every themable option +to its default value: + +---- +/theme reset +---- + +A backup is written first (same gate as `+/theme apply+`); on backup +failure the reset is aborted before any option is changed. +`+weechat.look.theme+` is cleared too. + [[themes_save_delete]] ==== Saving and deleting user themes diff --git a/doc/ja/weechat_user.ja.adoc b/doc/ja/weechat_user.ja.adoc index d5073e594..a353d861c 100644 --- a/doc/ja/weechat_user.ja.adoc +++ b/doc/ja/weechat_user.ja.adoc @@ -2426,6 +2426,20 @@ is aborted before any option is changed. The name of the last applied theme is stored in `+weechat.look.theme+` (informational only; not re-applied at startup). +[[themes_reset]] +==== Resetting to defaults + +To restore the look shipped with WeeChat, reset every themable option +to its default value: + +---- +/theme reset +---- + +A backup is written first (same gate as `+/theme apply+`); on backup +failure the reset is aborted before any option is changed. +`+weechat.look.theme+` is cleared too. + [[themes_save_delete]] ==== Saving and deleting user themes diff --git a/doc/pl/weechat_user.pl.adoc b/doc/pl/weechat_user.pl.adoc index 9494b1529..878c91fdb 100644 --- a/doc/pl/weechat_user.pl.adoc +++ b/doc/pl/weechat_user.pl.adoc @@ -2242,6 +2242,20 @@ is aborted before any option is changed. The name of the last applied theme is stored in `+weechat.look.theme+` (informational only; not re-applied at startup). +[[themes_reset]] +==== Resetting to defaults + +To restore the look shipped with WeeChat, reset every themable option +to its default value: + +---- +/theme reset +---- + +A backup is written first (same gate as `+/theme apply+`); on backup +failure the reset is aborted before any option is changed. +`+weechat.look.theme+` is cleared too. + [[themes_save_delete]] ==== Saving and deleting user themes diff --git a/doc/sr/weechat_user.sr.adoc b/doc/sr/weechat_user.sr.adoc index b25544cd5..41173e1f4 100644 --- a/doc/sr/weechat_user.sr.adoc +++ b/doc/sr/weechat_user.sr.adoc @@ -2144,6 +2144,20 @@ is aborted before any option is changed. The name of the last applied theme is stored in `+weechat.look.theme+` (informational only; not re-applied at startup). +[[themes_reset]] +==== Resetting to defaults + +To restore the look shipped with WeeChat, reset every themable option +to its default value: + +---- +/theme reset +---- + +A backup is written first (same gate as `+/theme apply+`); on backup +failure the reset is aborted before any option is changed. +`+weechat.look.theme+` is cleared too. + [[themes_save_delete]] ==== Saving and deleting user themes diff --git a/src/core/core-command.c b/src/core/core-command.c index b60ee5afb..9671e3391 100644 --- a/src/core/core-command.c +++ b/src/core/core-command.c @@ -7333,6 +7333,12 @@ COMMAND_CALLBACK(theme) return theme_apply (argv[2]); } + /* "/theme reset": reset every themable option to its default value */ + if (string_strcmp (argv[1], "reset") == 0) + { + return theme_reset (); + } + /* "/theme save [-full]": write a user theme file */ if (string_strcmp (argv[1], "save") == 0) { @@ -10073,6 +10079,7 @@ command_init (void) /* TRANSLATORS: only text between angle brackets (eg: "") may be translated */ N_("[list [-backups]]" " || apply " + " || reset" " || save [-full]" " || delete " " || info "), @@ -10086,6 +10093,8 @@ command_init (void) "value from the theme); if a file named .theme " "exists in directory \"themes\" it shadows any built-in " "theme of the same name"), + N_("raw[reset]: reset every themable option to its default " + "value (restores the original look shipped with WeeChat)"), N_("raw[save]: save current themable options to a file " ".theme in directory \"themes\"; by default only " "options whose value differs from their default are " @@ -10112,6 +10121,7 @@ command_init (void) "weechat.look.theme_backup.")), "list -backups" " || apply %(theme_themes_all)" + " || reset" " || save %(theme_themes_user) -full" " || delete %(theme_themes_user)" " || info %(theme_themes_all)", diff --git a/src/core/core-theme.c b/src/core/core-theme.c index b5180d9b7..22378fa90 100644 --- a/src/core/core-theme.c +++ b/src/core/core-theme.c @@ -1025,6 +1025,84 @@ theme_apply (const char *name) return WEECHAT_RC_OK; } +/* + * Resets every themable option to its default value. + * + * Same backup-first safety as theme_apply: if weechat.look.theme_backup + * is on, a backup file is written before any option is touched, and the + * reset is aborted if the backup cannot be written. The active-theme + * label (weechat.look.theme) is reset to its default (empty string). + * + * Returns WEECHAT_RC_OK on success, WEECHAT_RC_ERROR if the backup is + * required but failed. + */ + +int +theme_reset (void) +{ + struct t_config_file *ptr_config; + struct t_config_section *ptr_section; + struct t_config_option *ptr_option; + char *backup_name = NULL; + + if (CONFIG_BOOLEAN(config_look_theme_backup)) + { + backup_name = theme_make_backup (); + if (!backup_name) + { + gui_chat_printf ( + NULL, + _("%sUnable to create theme backup; aborting reset " + "(disable option weechat.look.theme_backup to force)"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + return WEECHAT_RC_ERROR; + } + } + + /* reset every themable option to its default value; per-option gui + refreshes are suppressed via theme_applying */ + theme_applying = 1; + for (ptr_config = config_files; ptr_config; + ptr_config = ptr_config->next_config) + { + for (ptr_section = ptr_config->sections; ptr_section; + ptr_section = ptr_section->next_section) + { + for (ptr_option = ptr_section->options; ptr_option; + ptr_option = ptr_option->next_option) + { + if (ptr_option->themable) + config_file_option_reset (ptr_option, 1); + } + } + } + theme_applying = 0; + + if (gui_init_ok) + { + gui_color_init_weechat (); + gui_window_ask_refresh (1); + } + + /* clear active-theme label */ + config_file_option_reset (config_look_theme, 1); + + if (backup_name) + { + gui_chat_printf ( + NULL, + _("Previous state saved as theme \"%s\"; to restore: " + "/theme apply %s"), + backup_name, backup_name); + free (backup_name); + } + + hook_signal_send ("theme_applied", + WEECHAT_HOOK_SIGNAL_STRING, (char *)""); + + return WEECHAT_RC_OK; +} + /* * Saves the current themable options to a user theme file. * diff --git a/src/core/core-theme.h b/src/core/core-theme.h index 2f51848c8..bd3ea80a3 100644 --- a/src/core/core-theme.h +++ b/src/core/core-theme.h @@ -69,6 +69,7 @@ extern const char *theme_get_override (struct t_theme *theme, const char *option_name); extern struct t_arraylist *theme_list (void); extern int theme_apply (const char *name); +extern int theme_reset (void); extern int theme_save (const char *name, int full); extern int theme_delete (const char *name); extern char *theme_make_backup (void); diff --git a/tests/unit/core/test-core-theme.cpp b/tests/unit/core/test-core-theme.cpp index 869118097..e9a8f2943 100644 --- a/tests/unit/core/test-core-theme.cpp +++ b/tests/unit/core/test-core-theme.cpp @@ -664,6 +664,56 @@ TEST(CoreTheme, ApplyMergeAcrossContributions) free (saved_value); } +/* + * Test functions: + * theme_reset + */ + +TEST(CoreTheme, Reset) +{ + struct t_hashtable *overrides; + struct t_config_option *opt_prefix_error; + char *saved_prefix_error, *saved_theme_label, *default_prefix_error; + int saved_backup; + + opt_prefix_error = NULL; + config_file_search_with_string ("weechat.look.prefix_error", + NULL, NULL, &opt_prefix_error, NULL); + CHECK(opt_prefix_error != NULL); + saved_prefix_error = strdup (CONFIG_STRING(opt_prefix_error)); + saved_theme_label = strdup (CONFIG_STRING(config_look_theme)); + saved_backup = CONFIG_BOOLEAN(config_look_theme_backup); + default_prefix_error = strdup (CONFIG_STRING_DEFAULT(opt_prefix_error)); + + config_file_option_set (config_look_theme_backup, "off", 1); + + /* set up a non-default state: apply a theme that flips one option + and sets weechat.look.theme as a side effect */ + overrides = make_overrides ("weechat.look.prefix_error", "RESET_ME!", + NULL, NULL); + theme_register (NULL, NULL, "reset_test", overrides); + hashtable_free (overrides); + LONGS_EQUAL(WEECHAT_RC_OK, theme_apply ("reset_test")); + STRCMP_EQUAL("RESET_ME!", CONFIG_STRING(opt_prefix_error)); + STRCMP_EQUAL("reset_test", CONFIG_STRING(config_look_theme)); + + /* reset: themable option goes back to its default, label is cleared */ + LONGS_EQUAL(WEECHAT_RC_OK, theme_reset ()); + STRCMP_EQUAL(default_prefix_error, CONFIG_STRING(opt_prefix_error)); + STRCMP_EQUAL(CONFIG_STRING_DEFAULT(config_look_theme), + CONFIG_STRING(config_look_theme)); + + /* restore */ + config_file_option_set (opt_prefix_error, saved_prefix_error, 1); + config_file_option_set (config_look_theme, saved_theme_label, 1); + config_file_option_set (config_look_theme_backup, + (saved_backup) ? "on" : "off", 1); + + free (saved_prefix_error); + free (saved_theme_label); + free (default_prefix_error); +} + /* * Test functions: * theme_file_strip_quotes