1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-12 14:14:48 +02:00

core: always write all options in theme files

Theme files saved with /theme save and automatic backups now always
contain every themable option (full snapshot), so a theme file is
self-contained and round-trips exactly regardless of the current
configuration. The diff-only mode and the "-full" argument of
/theme save are removed.
This commit is contained in:
Sébastien Helleu
2026-05-29 21:43:46 +02:00
parent a98568788b
commit d4ed290a37
11 changed files with 55 additions and 132 deletions
+3 -7
View File
@@ -2271,13 +2271,9 @@ Save the current themable options as a new user theme file:
/theme save mytheme
----
By default only options whose value differs from their hardcoded
default are written, keeping the file small and focused. To capture
every themable option:
----
/theme save mytheme -full
----
Every themable option is written, so the file is self-contained and
applies the exact same look on any WeeChat, regardless of its current
configuration.
Reserved names (built-in theme names like `+light+` and any name
starting with `+backup-+`) are refused. Files live at
+3 -7
View File
@@ -2258,13 +2258,9 @@ Save the current themable options as a new user theme file:
/theme save mytheme
----
By default only options whose value differs from their hardcoded
default are written, keeping the file small and focused. To capture
every themable option:
----
/theme save mytheme -full
----
Every themable option is written, so the file is self-contained and
applies the exact same look on any WeeChat, regardless of its current
configuration.
Reserved names (built-in theme names like `+light+` and any name
starting with `+backup-+`) are refused. Files live at
+3 -7
View File
@@ -2307,13 +2307,9 @@ thème utilisateur :
/theme save monTheme
----
Par défaut, seules les options dont la valeur diffère de la valeur par
défaut codée en dur sont écrites, ce qui garde le fichier compact et
ciblé. Pour capturer toutes les options modifiables :
----
/theme save monTheme -full
----
Toutes les options modifiables sont écrites, donc le fichier est
autonome et applique exactement le même aspect sur n'importe quel
WeeChat, quelle que soit sa configuration actuelle.
Les noms réservés (noms de thèmes intégrés comme `+light+` et tout nom
commençant par `+backup-+`) sont refusés. Les fichiers sont placés
+3 -7
View File
@@ -2513,13 +2513,9 @@ Save the current themable options as a new user theme file:
/theme save mytheme
----
By default only options whose value differs from their hardcoded
default are written, keeping the file small and focused. To capture
every themable option:
----
/theme save mytheme -full
----
Every themable option is written, so the file is self-contained and
applies the exact same look on any WeeChat, regardless of its current
configuration.
Reserved names (built-in theme names like `+light+` and any name
starting with `+backup-+`) are refused. Files live at
+3 -7
View File
@@ -2449,13 +2449,9 @@ Save the current themable options as a new user theme file:
/theme save mytheme
----
By default only options whose value differs from their hardcoded
default are written, keeping the file small and focused. To capture
every themable option:
----
/theme save mytheme -full
----
Every themable option is written, so the file is self-contained and
applies the exact same look on any WeeChat, regardless of its current
configuration.
Reserved names (built-in theme names like `+light+` and any name
starting with `+backup-+`) are refused. Files live at
+3 -7
View File
@@ -2265,13 +2265,9 @@ Save the current themable options as a new user theme file:
/theme save mytheme
----
By default only options whose value differs from their hardcoded
default are written, keeping the file small and focused. To capture
every themable option:
----
/theme save mytheme -full
----
Every themable option is written, so the file is self-contained and
applies the exact same look on any WeeChat, regardless of its current
configuration.
Reserved names (built-in theme names like `+light+` and any name
starting with `+backup-+`) are refused. Files live at
+3 -7
View File
@@ -2167,13 +2167,9 @@ Save the current themable options as a new user theme file:
/theme save mytheme
----
By default only options whose value differs from their hardcoded
default are written, keeping the file small and focused. To capture
every themable option:
----
/theme save mytheme -full
----
Every themable option is written, so the file is self-contained and
applies the exact same look on any WeeChat, regardless of its current
configuration.
Reserved names (built-in theme names like `+light+` and any name
starting with `+backup-+`) are refused. Files live at
+7 -11
View File
@@ -7339,14 +7339,11 @@ COMMAND_CALLBACK(theme)
return theme_reset ();
}
/* "/theme save <name> [-full]": write a user theme file */
/* "/theme save <name>": write a user theme file */
if (string_strcmp (argv[1], "save") == 0)
{
COMMAND_MIN_ARGS(3, "save");
return theme_save (argv[2],
((argc >= 4)
&& (string_strcmp (argv[3], "-full") == 0))
? 1 : 0);
return theme_save (argv[2]);
}
/* "/theme rename <old> <new>": rename a user theme file */
@@ -10087,7 +10084,7 @@ command_init (void)
N_("[list [-backups]]"
" || apply <name>"
" || reset"
" || save <name> [-full]"
" || save <name>"
" || rename <old> <new>"
" || delete <name>"
" || info <name>"),
@@ -10104,10 +10101,9 @@ command_init (void)
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 "
"<name>.theme in directory \"themes\"; by default only "
"options whose value differs from their default are "
"written, use \"-full\" to write every themable option; "
"the name must not match a built-in theme or start with "
"<name>.theme in directory \"themes\"; every themable "
"option is written, so the file is self-contained; the "
"name must not match a built-in theme or start with "
"\"backup-\""),
N_("raw[rename]: rename a user theme file (typically to "
"give an automatic backup a meaningful name); refuses to "
@@ -10135,7 +10131,7 @@ command_init (void)
"list -backups"
" || apply %(theme_themes_all)"
" || reset"
" || save %(theme_themes_user) -full"
" || save %(theme_themes_user)"
" || rename %(theme_themes_files)"
" || delete %(theme_themes_user)"
" || info %(theme_themes_all)",
+10 -17
View File
@@ -543,11 +543,9 @@ theme_make_backup_name (void)
* The themes directory is created if missing.
*
* The file contains an [info] section (name, description, date, weechat version)
* followed by an [options] section.
*
* If "diff_only" is non-zero, only options whose value differs from
* their default (config_file_option_has_changed) are written. If zero,
* every themable option is written (full snapshot).
* followed by an [options] section. Every themable option is always
* written (full snapshot), so a theme file is self-contained and round-trips
* exactly, regardless of the current configuration.
*
* Return path to saved file on success, NULL on error.
*
@@ -555,7 +553,7 @@ theme_make_backup_name (void)
*/
char *
theme_write_file (const char *name, const char *description, int diff_only)
theme_write_file (const char *name, const char *description)
{
char *path, *dir, *value, *now;
FILE *file;
@@ -606,8 +604,6 @@ theme_write_file (const char *name, const char *description, int diff_only)
{
if (!ptr_option->themable)
continue;
if (diff_only && !config_file_option_has_changed (ptr_option))
continue;
value = config_file_option_value_to_string (
ptr_option, 0, 0, 1);
fprintf (file, "%s.%s.%s = %s\n",
@@ -639,10 +635,7 @@ theme_make_backup (void)
name = theme_make_backup_name ();
if (!name)
return NULL;
path = theme_write_file (
name,
_("Automatic backup"),
0); /* full snapshot: backups must round-trip exactly */
path = theme_write_file (name, _("Automatic backup"));
if (!path)
{
free (name);
@@ -1124,16 +1117,16 @@ theme_reset (void)
* Save the current themable options to a user theme file.
*
* Refuse names that match a built-in theme (registered via API) or
* that start with "backup-" (reserved for automatic backups). If
* "full" is non-zero, every themable option is written; otherwise
* only options whose value differs from their default are written.
* that start with "backup-" (reserved for automatic backups). Every
* themable option is written (full snapshot), so the file is
* self-contained and round-trips exactly.
*
* Return WEECHAT_RC_OK on success, WEECHAT_RC_ERROR on validation or
* I/O failure.
*/
int
theme_save (const char *name, int full)
theme_save (const char *name)
{
char *path;
@@ -1160,7 +1153,7 @@ theme_save (const char *name, int full)
return WEECHAT_RC_ERROR;
}
path = theme_write_file (name, NULL, (full) ? 0 : 1);
path = theme_write_file (name, NULL);
if (!path)
{
gui_chat_printf (NULL,
+1 -1
View File
@@ -70,7 +70,7 @@ extern const char *theme_get_override (struct t_theme *theme,
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_save (const char *name);
extern int theme_rename (const char *old_name, const char *new_name);
extern int theme_delete (const char *name);
extern char *theme_make_backup (void);
+16 -54
View File
@@ -48,7 +48,7 @@ extern struct t_theme *theme_alloc (const char *name);
extern void theme_free (struct t_theme *theme);
extern char *theme_user_file_path (const char *name);
extern char *theme_make_backup_name (void);
extern char * theme_write_file (const char *name, const char *description, int diff_only);
extern char *theme_write_file (const char *name, const char *description);
extern char *theme_file_strip_quotes (char *value);
extern struct t_theme *theme_file_parse (const char *path);
}
@@ -340,18 +340,18 @@ TEST(CoreTheme, WriteFile)
char *path, *expected_path, line[8192];
FILE *file;
int saw_info, saw_name, saw_description, saw_date, saw_weechat;
int saw_options_section, full_options, diff_options;
int saw_options_section, full_options;
/* refuse empty/NULL */
POINTERS_EQUAL(NULL, theme_write_file (NULL, NULL, 0));
POINTERS_EQUAL(NULL, theme_write_file ("", NULL, 0));
POINTERS_EQUAL(NULL, theme_write_file (NULL, NULL));
POINTERS_EQUAL(NULL, theme_write_file ("", NULL));
/* full snapshot: every themable option is written; the returned
path matches the expected theme file path */
expected_path = theme_user_file_path ("test_wrt");
CHECK(expected_path != NULL);
path = theme_write_file ("test_wrt", "a description", 0);
path = theme_write_file ("test_wrt", "a description");
CHECK(path != NULL);
STRCMP_EQUAL(expected_path, path);
free (path);
@@ -392,34 +392,6 @@ TEST(CoreTheme, WriteFile)
LONGS_EQUAL(1, saw_options_section);
CHECK(full_options > 10); /* core has many themable options */
unlink (path);
/* diff-only snapshot in a freshly initialized config writes very
few (typically zero) [options] entries — never more than the
full snapshot */
path = theme_write_file ("test_wrt", NULL, 1);
CHECK(path != NULL);
STRCMP_EQUAL(expected_path, path);
free (path);
path = expected_path;
file = fopen (path, "r");
CHECK(file != NULL);
diff_options = 0;
saw_options_section = 0;
while (fgets (line, sizeof (line) - 1, file))
{
if (strncmp (line, "[options]", 9) == 0)
saw_options_section = 1;
else if (saw_options_section
&& (strchr (line, '=') != NULL)
&& (strchr (line, '.') != NULL))
diff_options++;
}
fclose (file);
CHECK(diff_options < full_options);
unlink (path);
free (path);
}
@@ -601,7 +573,7 @@ TEST(CoreTheme, ApplyFileShadowsBuiltin)
hashtable_free (overrides);
/* drop a same-named user file with a DIFFERENT value */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("user_throwaway", 0)); /* ensures themes dir exists */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("user_throwaway")); /* ensures themes dir exists */
path = theme_user_file_path ("shadow_test");
CHECK(path != NULL);
f = fopen (path, "w");
@@ -886,28 +858,18 @@ TEST(CoreTheme, Save)
struct stat st;
/* NULL / empty => error, no file */
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save (NULL, 0));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("", 0));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save (NULL));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save (""));
/* reserved "backup-" prefix => error */
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("backup-anything", 0));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("backup-anything", 1));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("backup-anything"));
/* name colliding with a built-in is refused */
theme_register (NULL, NULL, "dark", NULL);
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("dark", 0));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("dark", 1));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_save ("dark"));
/* happy path: sparse save => file exists */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("save_test", 0));
path = theme_user_file_path ("save_test");
CHECK(path != NULL);
LONGS_EQUAL(0, stat (path, &st));
unlink (path);
free (path);
/* happy path: full snapshot => file exists, bigger than sparse */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("save_test", 1));
/* happy path: full snapshot => file exists, with options written */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("save_test"));
path = theme_user_file_path ("save_test");
CHECK(path != NULL);
LONGS_EQUAL(0, stat (path, &st));
@@ -939,7 +901,7 @@ TEST(CoreTheme, Delete)
/* happy path: write a file via theme_save (also ensures the themes
directory exists), delete it, confirm it is gone */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("del_test", 0));
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("del_test"));
path = theme_user_file_path ("del_test");
CHECK(path != NULL);
LONGS_EQUAL(0, stat (path, &st));
@@ -973,7 +935,7 @@ TEST(CoreTheme, Rename)
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_rename ("dark", "renamed"));
/* refuses target == reserved "backup-" prefix */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("rn_src", 0));
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("rn_src"));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_rename ("rn_src", "backup-foo"));
/* refuses target == built-in name */
@@ -986,7 +948,7 @@ TEST(CoreTheme, Rename)
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_rename ("does_not_exist", "rn_dst"));
/* refuses target that already exists */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("rn_dst", 0));
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("rn_dst"));
LONGS_EQUAL(WEECHAT_RC_ERROR, theme_rename ("rn_src", "rn_dst"));
LONGS_EQUAL(WEECHAT_RC_OK, theme_delete ("rn_dst"));
@@ -1012,7 +974,7 @@ TEST(CoreTheme, Rename)
CHECK(strstr (buf, "name = \"rn_src\"") == NULL);
/* if weechat.look.theme pointed at the old name, the label moves too */
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("rn_active", 0));
LONGS_EQUAL(WEECHAT_RC_OK, theme_save ("rn_active"));
config_file_option_set (config_look_theme, "rn_active", 1);
LONGS_EQUAL(WEECHAT_RC_OK, theme_rename ("rn_active", "rn_moved"));
STRCMP_EQUAL("rn_moved", CONFIG_STRING(config_look_theme));