mirror of
https://github.com/weechat/weechat.git
synced 2026-07-05 17:23:15 +02:00
core: implement /theme save and /theme del
Add two complementary subcommands:
/theme save <name> [-full]: writes a user theme file at
${weechat_config_dir}/themes/<name>.theme containing the current
themable options. By default only options whose value differs from
their default (config_file_option_has_changed) are written, which
keeps the file small and focused. Pass "-full" to write every
themable option (matches the format used by automatic backups).
Name validation: refuses any name matching a built-in theme (those
are reserved for in-memory registrations) and any name starting
with "backup-" (reserved for /theme apply backups). Both checks
print an error and abort without writing.
/theme del <name>: removes ${weechat_config_dir}/themes/<name>.theme
via unlink. Refuses to delete a name registered as a built-in
theme (a built-in has no file on disk to delete, even if the user
has a shadowing file of the same name they cannot remove it this
way; they can rename or delete it manually).
The full-snapshot writer used by /theme apply backups is refactored
into theme_write_file (name, description, diff_only). It is reused
by theme_make_backup (diff_only=0) and theme_save (diff_only inverted
from the user's -full flag).
This commit is contained in:
+111
-5
@@ -312,12 +312,16 @@ theme_make_backup_name (void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a full snapshot of every themable option to a .theme file at
|
||||
* Write a snapshot of themable options to a .theme file at
|
||||
* "<weechat_config_dir>/themes/<name>.theme".
|
||||
*
|
||||
* The themes directory is created if missing. The file contains an
|
||||
* [info] section (name, description, date, weechat version) followed by
|
||||
* an [options] section listing every themable option's current value.
|
||||
* 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).
|
||||
*
|
||||
* Return:
|
||||
* 1: success
|
||||
@@ -325,7 +329,7 @@ theme_make_backup_name (void)
|
||||
*/
|
||||
|
||||
int
|
||||
theme_write_file_full (const char *name, const char *description)
|
||||
theme_write_file (const char *name, const char *description, int diff_only)
|
||||
{
|
||||
char *path, *dir, *value, *now;
|
||||
FILE *file;
|
||||
@@ -374,6 +378,8 @@ theme_write_file_full (const char *name, const char *description)
|
||||
{
|
||||
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",
|
||||
@@ -405,9 +411,10 @@ theme_make_backup (void)
|
||||
name = theme_make_backup_name ();
|
||||
if (!name)
|
||||
return NULL;
|
||||
if (!theme_write_file_full (
|
||||
if (!theme_write_file (
|
||||
name,
|
||||
_("Automatic backup written before /theme apply")))
|
||||
_("Automatic backup written before /theme apply"),
|
||||
0)) /* full snapshot: backups must round-trip exactly */
|
||||
{
|
||||
free (name);
|
||||
return NULL;
|
||||
@@ -785,6 +792,105 @@ theme_apply (const char *name)
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Return WEECHAT_RC_OK on success, WEECHAT_RC_ERROR on validation or
|
||||
* I/O failure.
|
||||
*/
|
||||
|
||||
int
|
||||
theme_save (const char *name, int full)
|
||||
{
|
||||
if (!name || !name[0])
|
||||
return WEECHAT_RC_ERROR;
|
||||
|
||||
if (strncmp (name, "backup-", 7) == 0)
|
||||
{
|
||||
gui_chat_printf (
|
||||
NULL,
|
||||
_("%sName \"%s\" is reserved for automatic backups"),
|
||||
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
||||
name);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
if (theme_search (name))
|
||||
{
|
||||
gui_chat_printf (
|
||||
NULL,
|
||||
_("%sName \"%s\" is reserved for a built-in theme"),
|
||||
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
||||
name);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
if (!theme_write_file (name, NULL, (full) ? 0 : 1))
|
||||
{
|
||||
gui_chat_printf (NULL,
|
||||
_("%sFailed to save theme \"%s\""),
|
||||
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
||||
name);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
gui_chat_printf (NULL,
|
||||
_("Theme saved: %s"),
|
||||
name);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a user theme file.
|
||||
*
|
||||
* Refuse names registered as built-in themes (they have no file).
|
||||
* Return WEECHAT_RC_OK on success, WEECHAT_RC_ERROR otherwise.
|
||||
*/
|
||||
|
||||
int
|
||||
theme_delete (const char *name)
|
||||
{
|
||||
char *path;
|
||||
|
||||
if (!name || !name[0])
|
||||
return WEECHAT_RC_ERROR;
|
||||
|
||||
if (theme_search (name))
|
||||
{
|
||||
gui_chat_printf (
|
||||
NULL,
|
||||
_("%sCannot delete built-in theme \"%s\""),
|
||||
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
||||
name);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
path = theme_user_file_path (name);
|
||||
if (!path)
|
||||
return WEECHAT_RC_ERROR;
|
||||
|
||||
if (unlink (path) != 0)
|
||||
{
|
||||
gui_chat_printf (NULL,
|
||||
_("%sFailed to delete theme \"%s\""),
|
||||
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
||||
name);
|
||||
free (path);
|
||||
return WEECHAT_RC_ERROR;
|
||||
}
|
||||
|
||||
gui_chat_printf (NULL,
|
||||
_("Theme deleted: %s"),
|
||||
name);
|
||||
free (path);
|
||||
return WEECHAT_RC_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the theme subsystem.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user