2019-10-24 02:13:11 +00:00
|
|
|
#include "gtktexthistoryprivate.h"
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
# define DEBUG_COMMANDS
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GtkTextHistory *history;
|
|
|
|
GString *buf;
|
|
|
|
struct {
|
|
|
|
int insert;
|
|
|
|
int bound;
|
|
|
|
} selection;
|
|
|
|
guint can_redo : 1;
|
|
|
|
guint can_undo : 1;
|
|
|
|
guint is_modified : 1;
|
|
|
|
} Text;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
IGNORE = 0,
|
|
|
|
SET = 1,
|
|
|
|
UNSET = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
IGNORE_SELECT = 0,
|
|
|
|
DO_SELECT = 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
INSERT = 1,
|
|
|
|
INSERT_SEQ,
|
|
|
|
BACKSPACE,
|
|
|
|
DELETE_KEY,
|
|
|
|
UNDO,
|
|
|
|
REDO,
|
|
|
|
BEGIN_IRREVERSIBLE,
|
|
|
|
END_IRREVERSIBLE,
|
|
|
|
BEGIN_USER,
|
|
|
|
END_USER,
|
|
|
|
MODIFIED,
|
|
|
|
UNMODIFIED,
|
|
|
|
SELECT,
|
|
|
|
CHECK_SELECT,
|
|
|
|
SET_MAX_UNDO,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int kind;
|
|
|
|
int location;
|
|
|
|
int end_location;
|
|
|
|
const char *text;
|
|
|
|
const char *expected;
|
|
|
|
int can_undo;
|
|
|
|
int can_redo;
|
|
|
|
int is_modified;
|
|
|
|
int select;
|
|
|
|
} Command;
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_change_state (gpointer funcs_data,
|
|
|
|
gboolean is_modified,
|
|
|
|
gboolean can_undo,
|
|
|
|
gboolean can_redo)
|
|
|
|
{
|
|
|
|
Text *text = funcs_data;
|
|
|
|
|
|
|
|
text->is_modified = is_modified;
|
|
|
|
text->can_undo = can_undo;
|
|
|
|
text->can_redo = can_redo;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_insert (gpointer funcs_data,
|
|
|
|
guint begin,
|
|
|
|
guint end,
|
|
|
|
const char *text,
|
|
|
|
guint len)
|
|
|
|
{
|
|
|
|
Text *t = funcs_data;
|
|
|
|
|
|
|
|
#ifdef DEBUG_COMMANDS
|
|
|
|
g_printerr ("Insert Into '%s' (begin=%u end=%u text=%s)\n",
|
|
|
|
t->buf->str, begin, end, text);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
g_string_insert_len (t->buf, begin, text, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_delete (gpointer funcs_data,
|
|
|
|
guint begin,
|
|
|
|
guint end,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *expected_text,
|
2019-10-24 02:13:11 +00:00
|
|
|
guint len)
|
|
|
|
{
|
|
|
|
Text *t = funcs_data;
|
|
|
|
|
|
|
|
#ifdef DEBUG_COMMANDS
|
|
|
|
g_printerr ("Delete(begin=%u end=%u expected_text=%s)\n", begin, end, expected_text);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (end < begin)
|
|
|
|
{
|
|
|
|
guint tmp = end;
|
|
|
|
end = begin;
|
|
|
|
begin = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_cmpint (memcmp (t->buf->str + begin, expected_text, len), ==, 0);
|
|
|
|
|
|
|
|
if (end >= t->buf->len)
|
|
|
|
{
|
|
|
|
t->buf->len = begin;
|
|
|
|
t->buf->str[begin] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove (t->buf->str + begin,
|
|
|
|
t->buf->str + end,
|
|
|
|
t->buf->len - end);
|
|
|
|
g_string_truncate (t->buf, t->buf->len - (end - begin));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_select (gpointer funcs_data,
|
2020-07-24 13:54:49 +00:00
|
|
|
int selection_insert,
|
|
|
|
int selection_bound)
|
2019-10-24 02:13:11 +00:00
|
|
|
{
|
|
|
|
Text *text = funcs_data;
|
|
|
|
|
|
|
|
text->selection.insert = selection_insert;
|
|
|
|
text->selection.bound = selection_bound;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkTextHistoryFuncs funcs = {
|
|
|
|
do_change_state,
|
|
|
|
do_insert,
|
|
|
|
do_delete,
|
|
|
|
do_select,
|
|
|
|
};
|
|
|
|
|
|
|
|
static Text *
|
|
|
|
text_new (void)
|
|
|
|
{
|
|
|
|
Text *text = g_slice_new0 (Text);
|
|
|
|
|
|
|
|
text->history = gtk_text_history_new (&funcs, text);
|
|
|
|
text->buf = g_string_new (NULL);
|
|
|
|
text->selection.insert = -1;
|
|
|
|
text->selection.bound = -1;
|
|
|
|
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
text_free (Text *text)
|
|
|
|
{
|
|
|
|
g_object_unref (text->history);
|
|
|
|
g_string_free (text->buf, TRUE);
|
|
|
|
g_slice_free (Text, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_insert (const Command *cmd,
|
|
|
|
Text *text)
|
|
|
|
{
|
|
|
|
do_insert (text,
|
|
|
|
cmd->location,
|
|
|
|
cmd->location + g_utf8_strlen (cmd->text, -1),
|
|
|
|
cmd->text,
|
|
|
|
strlen (cmd->text));
|
|
|
|
gtk_text_history_text_inserted (text->history, cmd->location, cmd->text, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_delete_key (const Command *cmd,
|
|
|
|
Text *text)
|
|
|
|
{
|
|
|
|
do_delete (text,
|
|
|
|
cmd->location,
|
|
|
|
cmd->end_location,
|
|
|
|
cmd->text,
|
|
|
|
strlen (cmd->text));
|
|
|
|
gtk_text_history_text_deleted (text->history,
|
|
|
|
cmd->location,
|
|
|
|
cmd->end_location,
|
|
|
|
cmd->text,
|
|
|
|
ABS (cmd->end_location - cmd->location));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_undo (const Command *cmd,
|
|
|
|
Text *text)
|
|
|
|
{
|
|
|
|
gtk_text_history_undo (text->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
command_redo (const Command *cmd,
|
|
|
|
Text *text)
|
|
|
|
{
|
|
|
|
gtk_text_history_redo (text->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_selection (Text *text,
|
|
|
|
int begin,
|
|
|
|
int end)
|
|
|
|
{
|
|
|
|
gtk_text_history_selection_changed (text->history, begin, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_test (const Command *commands,
|
|
|
|
guint n_commands,
|
|
|
|
guint max_undo)
|
|
|
|
{
|
|
|
|
Text *text = text_new ();
|
|
|
|
|
|
|
|
if (max_undo)
|
|
|
|
gtk_text_history_set_max_undo_levels (text->history, max_undo);
|
|
|
|
|
|
|
|
for (guint i = 0; i < n_commands; i++)
|
|
|
|
{
|
|
|
|
const Command *cmd = &commands[i];
|
|
|
|
|
|
|
|
#ifdef DEBUG_COMMANDS
|
|
|
|
g_printerr ("%d: %d\n", i, cmd->kind);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (cmd->kind)
|
|
|
|
{
|
|
|
|
case INSERT:
|
|
|
|
command_insert (cmd, text);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INSERT_SEQ:
|
|
|
|
for (guint j = 0; cmd->text[j]; j++)
|
|
|
|
{
|
|
|
|
const char seqtext[2] = { cmd->text[j], 0 };
|
|
|
|
Command seq = { INSERT, cmd->location + j, 1, seqtext, NULL };
|
|
|
|
command_insert (&seq, text);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DELETE_KEY:
|
|
|
|
if (cmd->select == DO_SELECT)
|
|
|
|
set_selection (text, cmd->location, cmd->end_location);
|
|
|
|
else if (strlen (cmd->text) == 1)
|
|
|
|
set_selection (text, cmd->location, -1);
|
|
|
|
command_delete_key (cmd, text);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BACKSPACE:
|
|
|
|
if (cmd->select == DO_SELECT)
|
|
|
|
set_selection (text, cmd->location, cmd->end_location);
|
|
|
|
else if (strlen (cmd->text) == 1)
|
|
|
|
set_selection (text, cmd->end_location, -1);
|
|
|
|
command_delete_key (cmd, text);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UNDO:
|
|
|
|
command_undo (cmd, text);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REDO:
|
|
|
|
command_redo (cmd, text);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BEGIN_USER:
|
|
|
|
gtk_text_history_begin_user_action (text->history);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case END_USER:
|
|
|
|
gtk_text_history_end_user_action (text->history);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BEGIN_IRREVERSIBLE:
|
|
|
|
gtk_text_history_begin_irreversible_action (text->history);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case END_IRREVERSIBLE:
|
|
|
|
gtk_text_history_end_irreversible_action (text->history);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MODIFIED:
|
|
|
|
gtk_text_history_modified_changed (text->history, TRUE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case UNMODIFIED:
|
|
|
|
gtk_text_history_modified_changed (text->history, FALSE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SELECT:
|
|
|
|
gtk_text_history_selection_changed (text->history,
|
|
|
|
cmd->location,
|
|
|
|
cmd->end_location);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHECK_SELECT:
|
|
|
|
g_assert_cmpint (text->selection.insert, ==, cmd->location);
|
|
|
|
g_assert_cmpint (text->selection.bound, ==, cmd->end_location);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SET_MAX_UNDO:
|
|
|
|
/* Not ideal use of location, but fine */
|
|
|
|
gtk_text_history_set_max_undo_levels (text->history, cmd->location);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->expected)
|
|
|
|
g_assert_cmpstr (text->buf->str, ==, cmd->expected);
|
|
|
|
|
|
|
|
if (cmd->can_redo == SET)
|
|
|
|
g_assert_cmpint (text->can_redo, ==, TRUE);
|
|
|
|
else if (cmd->can_redo == UNSET)
|
|
|
|
g_assert_cmpint (text->can_redo, ==, FALSE);
|
|
|
|
|
|
|
|
if (cmd->can_undo == SET)
|
|
|
|
g_assert_cmpint (text->can_undo, ==, TRUE);
|
|
|
|
else if (cmd->can_undo == UNSET)
|
|
|
|
g_assert_cmpint (text->can_undo, ==, FALSE);
|
|
|
|
|
|
|
|
if (cmd->is_modified == SET)
|
|
|
|
g_assert_cmpint (text->is_modified, ==, TRUE);
|
|
|
|
else if (cmd->is_modified == UNSET)
|
|
|
|
g_assert_cmpint (text->is_modified, ==, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
text_free (text);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test1 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "test", "test", SET, UNSET },
|
|
|
|
{ INSERT, 2, -1, "s", "tesst", SET, UNSET },
|
|
|
|
{ INSERT, 3, -1, "ss", "tesssst", SET, UNSET },
|
|
|
|
{ DELETE_KEY, 2, 5, "sss", "test", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "tesssst", SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "test", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "tesssst", SET, SET },
|
|
|
|
{ DELETE_KEY, 0, 7, "tesssst", "", SET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "z", "z", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "tesssst", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "test", SET, SET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test2 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ BEGIN_IRREVERSIBLE, -1, -1, NULL, "", UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "this is a test", "this is a test", UNSET, UNSET },
|
|
|
|
{ END_IRREVERSIBLE, -1, -1, NULL, "this is a test", UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", UNSET, UNSET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test", UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "first", "firstthis is a test", UNSET, UNSET },
|
|
|
|
{ INSERT, 5, -1, " ", "first this is a test", UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, "first this is a test", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", UNSET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", UNSET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "first this is a test", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", UNSET, SET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test3 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT_SEQ, 0, -1, "this is a test of insertions.", "this is a test of insertions.", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test of", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "" , UNSET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "this", SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is", SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a", SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test", SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test of", SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test of insertions.", SET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test4 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "initial text", "initial text", SET, UNSET },
|
|
|
|
/* Barrier */
|
|
|
|
{ BEGIN_IRREVERSIBLE, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ END_IRREVERSIBLE, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "more text ", "more text initial text", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "initial text", UNSET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "initial text", UNSET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "more text initial text", SET, UNSET },
|
|
|
|
/* Barrier */
|
|
|
|
{ BEGIN_IRREVERSIBLE, UNSET, UNSET },
|
|
|
|
{ END_IRREVERSIBLE, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "more text initial text", UNSET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test5 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "initial text", "initial text", SET, UNSET },
|
|
|
|
{ DELETE_KEY, 0, 12, "initial text", "", SET, UNSET },
|
|
|
|
/* Add empty nested user action (should get ignored) */
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "initial text" },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test6 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT_SEQ, 0, -1, " \t\t this is some text", " \t\t this is some text", SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, " \t\t this is some", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, " \t\t this is", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, " \t\t this", SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test7 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ MODIFIED, -1, -1, NULL, NULL, UNSET, UNSET, SET },
|
|
|
|
{ UNMODIFIED, -1, -1, NULL, NULL, UNSET, UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "foo bar", "foo bar", SET, UNSET, UNSET },
|
|
|
|
{ MODIFIED, -1, -1, NULL, NULL, SET, UNSET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET, UNSET },
|
|
|
|
{ REDO, -1, -1, NULL, "foo bar", SET, UNSET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET, UNSET },
|
|
|
|
{ REDO, -1, -1, NULL, "foo bar", SET, UNSET, SET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test8 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "foo bar", "foo bar", SET, UNSET, UNSET },
|
|
|
|
{ MODIFIED, -1, -1, NULL, NULL, SET, UNSET, SET },
|
|
|
|
{ INSERT, 0, -1, "f", "ffoo bar", SET, UNSET, SET },
|
|
|
|
{ UNMODIFIED, -1, -1, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "foo bar", SET, SET, SET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "foo bar", SET, SET, SET },
|
|
|
|
{ REDO, -1, -1, NULL, "ffoo bar", SET, UNSET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test9 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "foo bar", "foo bar", SET, UNSET, UNSET },
|
|
|
|
{ DELETE_KEY, 0, 3, "foo", " bar", SET, UNSET, UNSET, DO_SELECT },
|
|
|
|
{ DELETE_KEY, 0, 4, " bar", "", SET, UNSET, UNSET, DO_SELECT },
|
|
|
|
{ UNDO, -1, -1, NULL, " bar", SET, SET, UNSET },
|
|
|
|
{ CHECK_SELECT, 0, 4, NULL, " bar", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "foo bar", SET, SET, UNSET },
|
|
|
|
{ CHECK_SELECT, 0, 3, NULL, "foo bar", SET, SET, UNSET },
|
|
|
|
{ BEGIN_IRREVERSIBLE, -1, -1, NULL, "foo bar", UNSET, UNSET, UNSET },
|
|
|
|
{ END_IRREVERSIBLE, -1, -1, NULL, "foo bar", UNSET, UNSET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test10 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ BEGIN_USER }, { INSERT, 0, -1, "t", "t", UNSET, UNSET, UNSET }, { END_USER },
|
|
|
|
{ BEGIN_USER }, { INSERT, 1, -1, " ", "t ", UNSET, UNSET, UNSET }, { END_USER },
|
|
|
|
{ BEGIN_USER }, { INSERT, 2, -1, "t", "t t", UNSET, UNSET, UNSET }, { END_USER },
|
|
|
|
{ BEGIN_USER }, { INSERT, 3, -1, "h", "t th", UNSET, UNSET, UNSET }, { END_USER },
|
|
|
|
{ BEGIN_USER }, { INSERT, 4, -1, "i", "t thi", UNSET, UNSET, UNSET }, { END_USER },
|
|
|
|
{ BEGIN_USER }, { INSERT, 5, -1, "s", "t this", UNSET, UNSET, UNSET }, { END_USER },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test11 (void)
|
|
|
|
{
|
|
|
|
/* Test backspace */
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT_SEQ, 0, -1, "insert some text", "insert some text", SET, UNSET, UNSET },
|
|
|
|
{ BACKSPACE, 15, 16, "t", "insert some tex", SET, UNSET, UNSET },
|
|
|
|
{ BACKSPACE, 14, 15, "x", "insert some te", SET, UNSET, UNSET },
|
|
|
|
{ BACKSPACE, 13, 14, "e", "insert some t", SET, UNSET, UNSET },
|
|
|
|
{ BACKSPACE, 12, 13, "t", "insert some ", SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "insert some text", SET, SET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test12 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT_SEQ, 0, -1, "this is a test\nmore", "this is a test\nmore", SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test\n", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test13 (void)
|
|
|
|
{
|
|
|
|
static const Command commands[] = {
|
|
|
|
{ INSERT_SEQ, 0, -1, "this is a test\nmore", "this is a test\nmore", SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test\n", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a test", SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a", UNSET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is a", UNSET, SET, UNSET },
|
|
|
|
{ SET_MAX_UNDO, 2, -1, NULL, "this is a", UNSET, SET, UNSET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test", SET, SET, UNSET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test\n", SET, UNSET, UNSET },
|
|
|
|
{ REDO, -1, -1, NULL, "this is a test\n", SET, UNSET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 3);
|
|
|
|
}
|
|
|
|
|
2021-07-16 02:19:57 +00:00
|
|
|
static void
|
|
|
|
test14 (void)
|
|
|
|
{
|
|
|
|
char *fill = g_strnfill (1024, 'x');
|
|
|
|
char *fill_after = g_strnfill (1025, 'x');
|
|
|
|
char *fill_after_2 = g_strdup_printf ("%s word", fill_after);
|
|
|
|
const Command commands[] = {
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, fill, fill, UNSET, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "x", fill_after, UNSET, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET, UNSET },
|
|
|
|
{ INSERT_SEQ, strlen(fill_after), -1, " word", fill_after_2, UNSET, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, fill_after, SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, fill, SET, SET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "", UNSET, SET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
|
|
|
|
g_free (fill);
|
2021-09-14 12:24:36 +00:00
|
|
|
g_free (fill_after);
|
|
|
|
g_free (fill_after_2);
|
2021-07-16 02:19:57 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 00:08:02 +00:00
|
|
|
static void
|
|
|
|
test_issue_4276 (void)
|
|
|
|
{
|
|
|
|
const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "this is some text", "this is some text", SET, UNSET, UNSET },
|
|
|
|
{ SELECT, 0, 17, NULL, "this is some text", SET, UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET, UNSET },
|
|
|
|
{ DELETE_KEY, 0, 17, "this is some text", "", UNSET, UNSET, UNSET },
|
|
|
|
{ INSERT, 0, -1, "z", "z", UNSET, UNSET, UNSET },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ INSERT, 1, -1, "zzz", "zzzz", SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "z", SET, SET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
2021-12-26 20:46:16 +00:00
|
|
|
static void
|
|
|
|
test_issue_4575 (void)
|
|
|
|
{
|
|
|
|
const Command commands[] = {
|
|
|
|
{ INSERT, 0, -1, "this is some text", "this is some text", SET, UNSET, UNSET },
|
|
|
|
{ SELECT, 5, 8, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ BEGIN_USER, -1, -1, NULL, NULL, UNSET, UNSET, UNSET },
|
|
|
|
{ DELETE_KEY, 5, 8, "is ", "this some text", UNSET, UNSET, UNSET, IGNORE_SELECT },
|
|
|
|
{ END_USER, -1, -1, NULL, NULL, SET, UNSET, UNSET },
|
|
|
|
{ UNDO, -1, -1, NULL, "this is some text", SET, SET, UNSET },
|
|
|
|
{ CHECK_SELECT, 5, 8, NULL, "this is some text", SET, SET, UNSET },
|
|
|
|
};
|
|
|
|
|
|
|
|
run_test (commands, G_N_ELEMENTS (commands), 0);
|
|
|
|
}
|
|
|
|
|
2019-10-24 02:13:11 +00:00
|
|
|
int
|
|
|
|
main (int argc,
|
|
|
|
char *argv[])
|
|
|
|
{
|
2021-05-26 11:11:47 +00:00
|
|
|
(g_test_init) (&argc, &argv, NULL);
|
|
|
|
|
2019-10-24 02:13:11 +00:00
|
|
|
g_test_add_func ("/Gtk/TextHistory/test1", test1);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test2", test2);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test3", test3);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test4", test4);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test5", test5);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test6", test6);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test7", test7);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test8", test8);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test9", test9);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test10", test10);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test11", test11);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test12", test12);
|
|
|
|
g_test_add_func ("/Gtk/TextHistory/test13", test13);
|
2021-07-16 02:19:57 +00:00
|
|
|
g_test_add_func ("/Gtk/TextHistory/test14", test14);
|
2021-09-23 00:08:02 +00:00
|
|
|
g_test_add_func ("/Gtk/TextHistory/issue_4276", test_issue_4276);
|
2021-12-26 20:46:16 +00:00
|
|
|
g_test_add_func ("/Gtk/TextHistory/issue_4575", test_issue_4575);
|
2021-05-26 11:11:47 +00:00
|
|
|
|
2019-10-24 02:13:11 +00:00
|
|
|
return g_test_run ();
|
|
|
|
}
|