mirror of https://github.com/GNOME/gimp.git
SF Console history persist as GStrv setting.
Other driveby format and wording changes to dialog title, welcome text. Part of issue 9579 SF roadmap
This commit is contained in:
parent
691ec70c0e
commit
7b9b5db69e
|
@ -53,7 +53,9 @@ console_editor_set_text_and_position (GtkWidget *self,
|
|||
const gchar *text,
|
||||
gint position)
|
||||
{
|
||||
gtk_entry_set_text (GTK_ENTRY (self), text);
|
||||
/* gtk_entry_set_text not allow NULL */
|
||||
if (text != NULL)
|
||||
gtk_entry_set_text (GTK_ENTRY (self), text);
|
||||
gtk_editable_set_position (GTK_EDITABLE (self), position);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,13 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "libgimp/gimp.h"
|
||||
|
||||
#include "script-fu-console-history.h"
|
||||
|
||||
static gint console_history_tail_position (CommandHistory *self);
|
||||
static GStrv console_history_to_strv (CommandHistory *self);
|
||||
|
||||
|
||||
/* CommandHistory
|
||||
*
|
||||
|
@ -60,24 +63,22 @@
|
|||
* !!! Self does not currently write TotalHistory;
|
||||
* The main console logic writes TotalHistory,
|
||||
*
|
||||
* FUTURE:
|
||||
* CommandHistory is persistent across sessions of the ScriptFu Console,
|
||||
* and across sessions of Gimp.
|
||||
* When the SFConsole starts, the TotalHistory,
|
||||
* is just the CommandHistory, without results.
|
||||
* is just the CommandHistory, without results of eval.
|
||||
* Old results are not meaningful since the environment changed.
|
||||
* Specifically, a new session of SFConsole has a new initialized interpreter.
|
||||
* Similarly, when the user quits the console,
|
||||
* Similarly, when the user closes the console,
|
||||
* only the CommandHistory is saved as settings.
|
||||
*/
|
||||
|
||||
void
|
||||
console_history_init (CommandHistory *self,
|
||||
GtkTextBuffer *model_of_view)
|
||||
console_history_init (CommandHistory *self)
|
||||
{
|
||||
self->model = g_list_append (self->model, NULL);
|
||||
self->model_len = 1;
|
||||
self->model_max = 50;
|
||||
self->model_max = 100;
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,7 +99,7 @@ console_history_set_tail (CommandHistory *self,
|
|||
GList *list;
|
||||
|
||||
list = g_list_nth (self->model,
|
||||
(g_list_length (self->model) - 1));
|
||||
console_history_tail_position (self));
|
||||
|
||||
if (list->data)
|
||||
g_free (list->data);
|
||||
|
@ -107,8 +108,30 @@ console_history_set_tail (CommandHistory *self,
|
|||
list->data = (gpointer) command;
|
||||
}
|
||||
|
||||
/* Allocate an empty element at tail of CommandHistory.
|
||||
* Prune head when max exceeded.
|
||||
/* Remove the head of the history and free its string.
|
||||
*
|
||||
* GList doesn't have such a direct method.
|
||||
* Search web to find this solution.
|
||||
* !!! g_list_remove does not free the data of the removed element.
|
||||
*
|
||||
* Remove the element whose data (a string)
|
||||
* matches the data of the first element.
|
||||
* Then free the data of the first element.
|
||||
*/
|
||||
static void
|
||||
console_history_remove_head (CommandHistory *self)
|
||||
{
|
||||
gpointer * data;
|
||||
|
||||
g_return_if_fail (self->model != NULL);
|
||||
|
||||
data = self->model->data;
|
||||
self->model = g_list_remove (self->model, data);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
/* Append NULL string at tail of CommandHistory.
|
||||
* Prune head when max exceeded, freeing the string.
|
||||
* Position the cursor at last element.
|
||||
*/
|
||||
void
|
||||
|
@ -118,23 +141,26 @@ console_history_new_tail (CommandHistory *self)
|
|||
|
||||
if (self->model_len == self->model_max)
|
||||
{
|
||||
/* FIXME: is this correct, seems to be double freeing the head. */
|
||||
self->model = g_list_remove (self->model, self->model->data);
|
||||
if (self->model->data)
|
||||
g_free (self->model->data);
|
||||
console_history_remove_head (self);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->model_len++;
|
||||
}
|
||||
|
||||
self->model_cursor = g_list_length (self->model) - 1;
|
||||
self->model_cursor = console_history_tail_position (self);
|
||||
}
|
||||
|
||||
void
|
||||
console_history_cursor_to_tail (CommandHistory *self)
|
||||
{
|
||||
self->model_cursor = console_history_tail_position (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
console_history_is_cursor_at_tail (CommandHistory *self)
|
||||
{
|
||||
return self->model_cursor == g_list_length (self->model) - 1;
|
||||
return self->model_cursor == console_history_tail_position (self);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -143,6 +169,7 @@ console_history_move_cursor (CommandHistory *self,
|
|||
{
|
||||
self->model_cursor += direction;
|
||||
|
||||
/* Clamp cursor in range [0, model_len-1] */
|
||||
if (self->model_cursor < 0)
|
||||
self->model_cursor = 0;
|
||||
|
||||
|
@ -154,4 +181,78 @@ const gchar *
|
|||
console_history_get_at_cursor (CommandHistory *self)
|
||||
{
|
||||
return g_list_nth (self->model, self->model_cursor)->data;
|
||||
}
|
||||
|
||||
|
||||
/* Methods for persisting history as a setting. */
|
||||
|
||||
/* Return a GStrv of the history from settings.
|
||||
* The Console knows how to put GStrv to both models!
|
||||
*
|
||||
* !!! Handle attack on settings file.
|
||||
* The returned cardinality of the set of strings
|
||||
* may be zero or very many.
|
||||
* Elsewhere ensure we don't overflow models.
|
||||
*/
|
||||
GStrv
|
||||
console_history_from_settings (CommandHistory *self,
|
||||
GimpProcedureConfig *config)
|
||||
{
|
||||
GStrv in_history;
|
||||
|
||||
/* Get aux arg from property of config. */
|
||||
g_object_get (config,
|
||||
"history", &in_history,
|
||||
NULL);
|
||||
|
||||
return in_history;
|
||||
}
|
||||
|
||||
void
|
||||
console_history_to_settings (CommandHistory *self,
|
||||
GimpProcedureConfig *config)
|
||||
{
|
||||
GStrv out_history;
|
||||
|
||||
out_history = console_history_to_strv (self);
|
||||
|
||||
/* set an aux arg in config. */
|
||||
g_object_set (config,
|
||||
"history", out_history,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Return history model as GStrv.
|
||||
* Converts from interal list into a string array.
|
||||
*
|
||||
* !!! The exported history may have a tail
|
||||
* which is user's edits to the command line,
|
||||
* that the user never evaluated.
|
||||
* Exported history does not have an empty tail.
|
||||
*
|
||||
* Caller must g_strfreev the returned GStrv.
|
||||
*/
|
||||
static GStrv
|
||||
console_history_to_strv (CommandHistory *self)
|
||||
{
|
||||
GStrv history_strv;
|
||||
GStrvBuilder *builder;
|
||||
|
||||
builder = g_strv_builder_new ();
|
||||
/* Order is earliest first. */
|
||||
for (GList *l = self->model; l != NULL; l = l->next)
|
||||
{
|
||||
/* Don't write an empty pre-allocated tail. */
|
||||
if (l->data != NULL)
|
||||
g_strv_builder_add (builder, l->data);
|
||||
}
|
||||
history_strv = g_strv_builder_end (builder);
|
||||
g_strv_builder_unref (builder);
|
||||
return history_strv;
|
||||
}
|
||||
|
||||
static gint
|
||||
console_history_tail_position (CommandHistory *self)
|
||||
{
|
||||
return g_list_length (self->model) - 1;
|
||||
}
|
|
@ -28,8 +28,7 @@ typedef struct
|
|||
} CommandHistory;
|
||||
|
||||
|
||||
void console_history_init (CommandHistory *self,
|
||||
GtkTextBuffer *total_history);
|
||||
void console_history_init (CommandHistory *self);
|
||||
|
||||
void console_history_new_tail (CommandHistory *self);
|
||||
void console_history_set_tail (CommandHistory *self,
|
||||
|
@ -37,8 +36,14 @@ void console_history_set_tail (CommandHistory *self,
|
|||
|
||||
void console_history_move_cursor (CommandHistory *self,
|
||||
gint direction);
|
||||
void console_history_cursor_to_tail (CommandHistory *self);
|
||||
gboolean console_history_is_cursor_at_tail (CommandHistory *self);
|
||||
const gchar *console_history_get_at_cursor (CommandHistory *self);
|
||||
|
||||
GStrv console_history_from_settings (CommandHistory *self,
|
||||
GimpProcedureConfig *config);
|
||||
void console_history_to_settings (CommandHistory *self,
|
||||
GimpProcedureConfig *config);
|
||||
|
||||
|
||||
#endif /* __SCRIPT_FU_CONSOLE_HISTORY_H__ */
|
||||
|
|
|
@ -86,13 +86,11 @@ console_total_append_welcome (GtkTextBuffer *self)
|
|||
{
|
||||
const gchar * const greetings[] =
|
||||
{
|
||||
"strong", N_("Welcome to TinyScheme"),
|
||||
"emphasis", N_("Welcome to TinyScheme"),
|
||||
NULL, "\n",
|
||||
NULL, "Copyright (c) Dimitrios Souflis",
|
||||
"emphasis", "Copyright (c) Dimitrios Souflis",
|
||||
NULL, "\n",
|
||||
"strong", N_("Script-Fu Console"),
|
||||
NULL, " - ",
|
||||
"emphasis", N_("Interactive Scheme Development"),
|
||||
"emphasis", N_("Scripting GIMP in the Scheme language"),
|
||||
NULL, "\n"
|
||||
};
|
||||
|
||||
|
@ -125,6 +123,7 @@ console_total_append_text_normal (GtkTextBuffer *self,
|
|||
|
||||
gtk_text_buffer_get_end_iter (self, &cursor);
|
||||
gtk_text_buffer_insert (self, &cursor, text, len);
|
||||
gtk_text_buffer_insert (self, &cursor, "\n", 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -139,6 +138,7 @@ console_total_append_text_emphasize (GtkTextBuffer *self,
|
|||
&cursor,
|
||||
text, len, "emphasis",
|
||||
NULL);
|
||||
gtk_text_buffer_insert (self, &cursor, "\n", 1);
|
||||
}
|
||||
|
||||
/* Write newlines, prompt, and command. */
|
||||
|
@ -150,7 +150,8 @@ console_total_append_command (GtkTextBuffer *self,
|
|||
|
||||
gtk_text_buffer_get_end_iter (self, &cursor);
|
||||
|
||||
gtk_text_buffer_insert (self, &cursor, "\n", 1);
|
||||
/* assert we are just after a newline. */
|
||||
|
||||
/* Write repr of a prompt.
|
||||
* SFConsole doesn't have a prompt in it's command line,
|
||||
* But we show one in the history view to distinguish commands.
|
||||
|
|
|
@ -80,12 +80,17 @@ static void script_fu_browse_row_activated (GtkDialog *dialog);
|
|||
static gboolean script_fu_editor_key_function (GtkWidget *widget,
|
||||
GdkEventKey *event,
|
||||
ConsoleInterface *console);
|
||||
|
||||
static void script_fu_console_scroll_end (GtkWidget *view);
|
||||
static void script_fu_output_to_console (gboolean is_error,
|
||||
const gchar *text,
|
||||
gint len,
|
||||
gpointer user_data);
|
||||
|
||||
static void script_fu_models_from_settings (ConsoleInterface *console,
|
||||
GimpProcedureConfig *config);
|
||||
static void script_fu_command_to_history (ConsoleInterface *console,
|
||||
const gchar *command);
|
||||
|
||||
/*
|
||||
* Function definitions
|
||||
*/
|
||||
|
@ -100,11 +105,24 @@ script_fu_console_run (GimpProcedure *procedure,
|
|||
GtkWidget *scrolled_window;
|
||||
GtkWidget *hbox;
|
||||
|
||||
GimpProcedureConfig *config;
|
||||
|
||||
script_fu_set_print_flag (1);
|
||||
|
||||
gimp_ui_init ("script-fu");
|
||||
|
||||
console.dialog = gimp_dialog_new (_("Script-Fu Console"),
|
||||
/* Create model early so we can fill from settings. */
|
||||
console.total_history = console_total_history_new ();
|
||||
console_history_init (&console.history);
|
||||
console_total_append_welcome (console.total_history);
|
||||
|
||||
/* Get previous or default settings into config. */
|
||||
config = gimp_procedure_create_config (procedure);
|
||||
gimp_procedure_config_begin_run (config, NULL, GIMP_RUN_INTERACTIVE, args);
|
||||
|
||||
script_fu_models_from_settings (&console, config);
|
||||
|
||||
console.dialog = gimp_dialog_new (_("Script Console"),
|
||||
"gimp-script-fu-console",
|
||||
NULL, 0,
|
||||
gimp_standard_help_func, PROC_NAME,
|
||||
|
@ -145,8 +163,6 @@ script_fu_console_run (GimpProcedure *procedure,
|
|||
gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scrolled_window);
|
||||
|
||||
console.total_history = console_total_history_new ();
|
||||
|
||||
console.history_view = gtk_text_view_new_with_buffer (console.total_history);
|
||||
/* View keeps reference. Unref our ref so buffer is destroyed with view. */
|
||||
g_object_unref (console.total_history);
|
||||
|
@ -160,8 +176,6 @@ script_fu_console_run (GimpProcedure *procedure,
|
|||
gtk_container_add (GTK_CONTAINER (scrolled_window), console.history_view);
|
||||
gtk_widget_show (console.history_view);
|
||||
|
||||
console_total_append_welcome (console.total_history);
|
||||
|
||||
/* An editor of a command to be executed. */
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
||||
|
@ -188,10 +202,11 @@ script_fu_console_run (GimpProcedure *procedure,
|
|||
G_CALLBACK (script_fu_browse_callback),
|
||||
&console);
|
||||
|
||||
console_history_init (&console.history, console.total_history);
|
||||
|
||||
gtk_widget_show (console.dialog);
|
||||
|
||||
/* The history model may fill the view, scroll. */
|
||||
script_fu_console_scroll_end (console.history_view);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
if (console.save_dialog)
|
||||
|
@ -200,6 +215,11 @@ script_fu_console_run (GimpProcedure *procedure,
|
|||
if (console.dialog)
|
||||
gtk_widget_destroy (console.dialog);
|
||||
|
||||
/* Update config with user's change to history */
|
||||
console_history_to_settings (&console.history, config);
|
||||
/* Persist config */
|
||||
gimp_procedure_config_end_run (config, GIMP_PDB_SUCCESS);
|
||||
|
||||
return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
|
||||
}
|
||||
|
||||
|
@ -425,12 +445,12 @@ script_fu_console_scroll_end (GtkWidget *view)
|
|||
g_idle_add ((GSourceFunc) script_fu_console_idle_scroll_end, view);
|
||||
}
|
||||
|
||||
/* Write results of execution to the console view.
|
||||
/* Write result of eval to the console view.
|
||||
* But not put results in the history model.
|
||||
*/
|
||||
static void
|
||||
script_fu_output_to_console (gboolean is_error_msg,
|
||||
const gchar *text,
|
||||
const gchar *result_text,
|
||||
gint len,
|
||||
gpointer user_data)
|
||||
{
|
||||
|
@ -439,9 +459,9 @@ script_fu_output_to_console (gboolean is_error_msg,
|
|||
if (console && console->history_view)
|
||||
{
|
||||
if (! is_error_msg)
|
||||
console_total_append_text_normal (console->total_history, text, len);
|
||||
console_total_append_text_normal (console->total_history, result_text, len);
|
||||
else
|
||||
console_total_append_text_emphasize (console->total_history, text, len);
|
||||
console_total_append_text_emphasize (console->total_history, result_text, len);
|
||||
|
||||
script_fu_console_scroll_end (console->history_view);
|
||||
}
|
||||
|
@ -468,16 +488,9 @@ script_fu_editor_key_function (GtkWidget *widget,
|
|||
return TRUE;
|
||||
|
||||
command = g_strdup (console_editor_get_text (console->editor));
|
||||
/* Put to history model.
|
||||
*
|
||||
* We own the command.
|
||||
* This transfers ownership to history model.
|
||||
* We retain a reference, used below, but soon out of scope.
|
||||
*/
|
||||
console_history_set_tail (&console->history, command);
|
||||
|
||||
/* Put decorated command to total_history, distinct from history model. */
|
||||
console_total_append_command (console->total_history, command);
|
||||
script_fu_command_to_history (console, command);
|
||||
/* Assert history advanced to new, empty tail. */
|
||||
|
||||
script_fu_console_scroll_end (console->history_view);
|
||||
|
||||
|
@ -503,8 +516,6 @@ script_fu_editor_key_function (GtkWidget *widget,
|
|||
|
||||
gimp_displays_flush ();
|
||||
|
||||
console_history_new_tail (&console->history);
|
||||
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
|
@ -531,6 +542,11 @@ script_fu_editor_key_function (GtkWidget *widget,
|
|||
break;
|
||||
|
||||
default:
|
||||
/* Any other key is the user editing.
|
||||
* Set cursor to tail: user is done scrolling history.
|
||||
* Must do this to ensure edited command line is saved in history.
|
||||
*/
|
||||
console_history_cursor_to_tail (&console->history);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -541,12 +557,14 @@ script_fu_editor_key_function (GtkWidget *widget,
|
|||
* So any edited text is not lost if user moves cursor back to tail.
|
||||
*/
|
||||
command = console_editor_get_text (console->editor);
|
||||
/* command can be NULL */
|
||||
if (console_history_is_cursor_at_tail (&console->history))
|
||||
console_history_set_tail (&console->history, g_strdup (command));
|
||||
|
||||
/* Now move cursor and replace editor contents. */
|
||||
console_history_move_cursor (&console->history, direction);
|
||||
command = console_history_get_at_cursor (&console->history);
|
||||
/* command can be NULL. */
|
||||
console_editor_set_text_and_position (console->editor,
|
||||
command,
|
||||
-1);
|
||||
|
@ -555,4 +573,70 @@ script_fu_editor_key_function (GtkWidget *widget,
|
|||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Restore models from settings.
|
||||
* This understands how to get history as a GStrv from settings
|
||||
* and how to put GStrv into both models.
|
||||
*
|
||||
* Just the model. The view does not exist yet.
|
||||
*/
|
||||
static void
|
||||
script_fu_models_from_settings (ConsoleInterface *console,
|
||||
GimpProcedureConfig *config)
|
||||
|
||||
{
|
||||
GStrv strings_in;
|
||||
|
||||
/* Assert the History model is empty, recently init. */
|
||||
|
||||
strings_in = console_history_from_settings (&console->history, config);
|
||||
|
||||
/* The history setting can be empty, and GStrv can be NULL.
|
||||
* !!! But g_strv_length requires its arg!=NULL
|
||||
*/
|
||||
if (strings_in==NULL)
|
||||
return;
|
||||
|
||||
/* Adding requires a new tail. */
|
||||
console_history_new_tail (&console->history);
|
||||
|
||||
/* Order of the GStrv is earliest command first.
|
||||
* Iterate ascending, i.e. earliest command to history first.
|
||||
* Not concerned with performance.
|
||||
*/
|
||||
for (gint i = 0; i < g_strv_length (strings_in); i++)
|
||||
script_fu_command_to_history (console, g_strdup (strings_in[i]));
|
||||
|
||||
g_strfreev (strings_in);
|
||||
}
|
||||
|
||||
|
||||
/* Append a command to history.
|
||||
*
|
||||
* Knows to put to both TotalHistory and History models.
|
||||
*
|
||||
* Transfers ownership of command to History model.
|
||||
* Caller may retain a reference, for a short time.
|
||||
*
|
||||
* !!! The History model is finite and limits itself.
|
||||
* While the TotalHistory model is nearly unlimited.
|
||||
* More commands in the view than in the History model.
|
||||
*/
|
||||
static void
|
||||
script_fu_command_to_history (ConsoleInterface *console,
|
||||
const gchar *command)
|
||||
{
|
||||
/* Require new_tail called previously. */
|
||||
|
||||
/* To History model. */
|
||||
console_history_set_tail (&console->history, command);
|
||||
|
||||
/* Advance history, editor wants preallocated tail. */
|
||||
console_history_new_tail (&console->history);
|
||||
|
||||
/* Decorated command to TotalHistory model. */
|
||||
console_total_append_command (console->total_history, command);
|
||||
|
||||
/* Ensure there is a new tail. */
|
||||
}
|
|
@ -140,6 +140,10 @@ script_fu_create_procedure (GimpPlugIn *plug_in,
|
|||
GIMP_TYPE_RUN_MODE,
|
||||
GIMP_RUN_INTERACTIVE,
|
||||
G_PARAM_READWRITE);
|
||||
GIMP_PROC_AUX_ARG_STRV (procedure, "history",
|
||||
"Command history",
|
||||
"History",
|
||||
G_PARAM_READWRITE);
|
||||
}
|
||||
else if (! strcmp (name, "plug-in-script-fu-text-console"))
|
||||
{
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
# marked to allow runtime translation of messages
|
||||
|
||||
plug-ins/script-fu/script-fu.c
|
||||
plug-ins/script-fu/script-fu-console.c
|
||||
plug-ins/script-fu/script-fu-eval.c
|
||||
plug-ins/script-fu/console/script-fu-console.c
|
||||
plug-ins/script-fu/console/script-fu-console-total.c
|
||||
plug-ins/script-fu/server/script-fu-server.c
|
||||
plug-ins/script-fu/server/script-fu-server-plugin.c
|
||||
plug-ins/script-fu/libscriptfu/script-fu-interface.c
|
||||
|
|
Loading…
Reference in New Issue