changeset 21266:1f59065c606a

Add 'yank' action in the entry boxes.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Fri, 26 Oct 2007 13:31:26 +0000
parents b2d3f529f500
children 83b9a8201cbd a41ac7fd19ab
files ChangeLog ChangeLog.API finch/libgnt/gntentry.c finch/libgnt/gntentry.h
diffstat 4 files changed, 129 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Oct 26 09:44:00 2007 +0000
+++ b/ChangeLog	Fri Oct 26 13:31:26 2007 +0000
@@ -24,6 +24,7 @@
 	  Read the 'Menus' section in the man-page for details.
 	* 'transpose-chars' operation for the entry boxes. The default key-binding
 	  is ctrl+t.
+	* 'yank' operation for the entry boxes. The default binding is ctrl+y.
 
 version 2.2.2:
 	http://developer.pidgin.im/query?status=closed&milestone=2.2.2
--- a/ChangeLog.API	Fri Oct 26 09:44:00 2007 +0000
+++ b/ChangeLog.API	Fri Oct 26 13:31:26 2007 +0000
@@ -108,6 +108,7 @@
 		  given id from a menu.
 		* Added gnt_menuitem_activate, which triggers the 'activate' signal on
 		  the menuitem and calls the callback function, if available.
+		* Added GntEntryKillRing in GntEntry.
 
 version 2.2.2 (??/??/????):
 	libpurple:
--- a/finch/libgnt/gntentry.c	Fri Oct 26 09:44:00 2007 +0000
+++ b/finch/libgnt/gntentry.c	Fri Oct 26 13:31:26 2007 +0000
@@ -36,6 +36,24 @@
 	SIG_COMPLETION,
 	SIGS,
 };
+
+typedef enum
+{
+	ENTRY_JAIL = -1,    /* Suspend the kill ring. */
+	ENTRY_DEL_BWD_WORD = 1,
+	ENTRY_DEL_BWD_CHAR,
+	ENTRY_DEL_FWD_WORD,
+	ENTRY_DEL_FWD_CHAR,
+	ENTRY_DEL_EOL,
+	ENTRY_DEL_BOL,
+} GntEntryAction;
+
+struct _GntEntryKillRing
+{
+	GString *buffer;
+	GntEntryAction last;
+};
+
 static guint signals[SIGS] = { 0 };
 
 static GntWidgetClass *parent_class = NULL;
@@ -43,6 +61,58 @@
 static gboolean gnt_entry_key_pressed(GntWidget *widget, const char *text);
 static void gnt_entry_set_text_internal(GntEntry *entry, const char *text);
 
+static gboolean
+update_kill_ring(GntEntry *entry, GntEntryAction action, const char *text, int len)
+{
+	if (action < 0) {
+		entry->killring->last = action;
+		return FALSE;
+	}
+
+	if (len == 0)
+		len = strlen(text);
+	else if (len < 0) {
+		text += len;
+		len = -len;
+	}
+
+	if (action != entry->killring->last) {
+		struct {
+			GntEntryAction one;
+			GntEntryAction two;
+		} merges[] = {
+			{ENTRY_DEL_BWD_WORD, ENTRY_DEL_FWD_WORD},
+			{ENTRY_DEL_BWD_CHAR, ENTRY_DEL_FWD_CHAR},
+			{ENTRY_DEL_BOL, ENTRY_DEL_EOL},
+			{ENTRY_JAIL, ENTRY_JAIL},
+		};
+		int i;
+
+		for (i = 0; merges[i].one != ENTRY_JAIL; i++) {
+			if (merges[i].one == entry->killring->last &&
+					merges[i].two == action) {
+				g_string_append_len(entry->killring->buffer, text, len);
+				break;
+			} else if (merges[i].one == action &&
+					merges[i].two == entry->killring->last) {
+				g_string_prepend_len(entry->killring->buffer, text, len);
+				break;
+			}
+		}
+		if (merges[i].one == ENTRY_JAIL) {
+			g_string_assign(entry->killring->buffer, text);
+			g_string_truncate(entry->killring->buffer, len);
+		}
+		entry->killring->last = action;
+	} else {
+		if (action == ENTRY_DEL_BWD_CHAR || action == ENTRY_DEL_BWD_WORD)
+			g_string_prepend_len(entry->killring->buffer, text, len);
+		else
+			g_string_append_len(entry->killring->buffer, text, len);
+	}
+	return TRUE;
+}
+
 static void
 destroy_suggest(GntEntry *entry)
 {
@@ -97,6 +167,7 @@
 	if (changed)
 		g_signal_emit(G_OBJECT(entry), signals[SIG_COMPLETION], 0,
 				entry->start + offstart, entry->start + offend);
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	return changed;
 }
 
@@ -264,6 +335,7 @@
 	entry->cursor = g_utf8_find_prev_char(entry->start, entry->cursor);
 	if (entry->cursor < entry->scroll)
 		entry->scroll = entry->cursor;
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(entry));
 	return TRUE;
 }
@@ -277,6 +349,7 @@
 	entry->cursor = g_utf8_find_next_char(entry->cursor, NULL);
 	while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width)
 		entry->scroll = g_utf8_find_next_char(entry->scroll, NULL);
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(entry));
 	return TRUE;
 }
@@ -289,9 +362,11 @@
 
 	if (entry->cursor <= entry->start)
 		return TRUE;
-	
+
 	len = entry->cursor - g_utf8_find_prev_char(entry->start, entry->cursor);
+	update_kill_ring(entry, ENTRY_DEL_BWD_CHAR, entry->cursor, -len);
 	entry->cursor -= len;
+
 	memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor);
 	entry->end -= len;
 
@@ -313,8 +388,9 @@
 
 	if (entry->cursor >= entry->end)
 		return FALSE;
-	
+
 	len = g_utf8_find_next_char(entry->cursor, NULL) - entry->cursor;
+	update_kill_ring(entry, ENTRY_DEL_FWD_CHAR, entry->cursor, len);
 	memmove(entry->cursor, entry->cursor + len, entry->end - entry->cursor - len + 1);
 	entry->end -= len;
 	entry_redraw(GNT_WIDGET(entry));
@@ -331,6 +407,7 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	entry->scroll = entry->cursor = entry->start;
 	entry_redraw(GNT_WIDGET(entry));
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	return TRUE;
 }
 
@@ -343,6 +420,7 @@
 	while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= GNT_WIDGET(entry)->priv.width)
 		entry->scroll = g_utf8_find_next_char(entry->scroll, NULL);
 	entry_redraw(GNT_WIDGET(entry));
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	return TRUE;
 }
 
@@ -357,6 +435,7 @@
 		destroy_suggest(entry);
 		entry_text_changed(entry);
 
+		update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 		return TRUE;
 	}
 	return FALSE;
@@ -381,6 +460,7 @@
 		destroy_suggest(entry);
 		entry_text_changed(entry);
 
+		update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 		return TRUE;
 	}
 	return FALSE;
@@ -400,6 +480,7 @@
 	a = g_strndup(entry->start, entry->cursor - entry->start);
 	all = g_strconcat(a, text, entry->cursor, NULL);
 	gnt_entry_set_text_internal(entry, all);
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	g_free(a);
 	g_free(text);
 	g_free(all);
@@ -445,6 +526,7 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	if (entry->cursor <= entry->start)
 		return TRUE;
+	update_kill_ring(entry, ENTRY_DEL_BOL, entry->start, entry->cursor - entry->start);
 	memmove(entry->start, entry->cursor, entry->end - entry->cursor);
 	entry->end -= (entry->cursor - entry->start);
 	entry->cursor = entry->scroll = entry->start;
@@ -460,6 +542,7 @@
 	GntEntry *entry = GNT_ENTRY(bind);
 	if (entry->end <= entry->cursor)
 		return TRUE;
+	update_kill_ring(entry, ENTRY_DEL_EOL, entry->cursor, entry->end - entry->cursor);
 	entry->end = entry->cursor;
 	memset(entry->end, '\0', entry->buffer - (entry->end - entry->start));
 	entry_redraw(GNT_WIDGET(bind));
@@ -517,6 +600,7 @@
 	entry->cursor = (char*)iter;
 	if (entry->cursor < entry->scroll)
 		entry->scroll = entry->cursor;
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(bind));
 	return TRUE;
 }
@@ -533,6 +617,7 @@
 		return TRUE;
 	iter = (char*)begin_word(iter, entry->start);
 	count = entry->cursor - iter;
+	update_kill_ring(entry, ENTRY_DEL_BWD_WORD, iter, count);
 	memmove(iter, entry->cursor, entry->end - entry->cursor);
 	entry->end -= count;
 	entry->cursor = iter;
@@ -557,6 +642,7 @@
 	while (gnt_util_onscreen_width(entry->scroll, entry->cursor) >= widget->priv.width) {
 		entry->scroll = g_utf8_find_next_char(entry->scroll, NULL);
 	}
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(widget);
 	return TRUE;
 }
@@ -570,6 +656,7 @@
 	int len = entry->end - iter + 1;
 	if (len <= 0)
 		return TRUE;
+	update_kill_ring(entry, ENTRY_DEL_FWD_WORD, entry->cursor, iter - entry->cursor);
 	memmove(entry->cursor, iter, len);
 	len = iter - entry->cursor;
 	entry->end -= len;
@@ -601,12 +688,21 @@
 	memmove(prev, current, entry->cursor - current);
 	memcpy(prev + (entry->cursor - current), hold, current - prev);
 
+	update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 	entry_redraw(GNT_WIDGET(entry));
 	entry_text_changed(entry);
 	return TRUE;
 }
 
 static gboolean
+entry_yank(GntBindable *bind, GList *null)
+{
+	GntEntry *entry = GNT_ENTRY(bind);
+	gnt_entry_key_pressed(GNT_WIDGET(entry), entry->killring->buffer->str);
+	return TRUE;
+}
+
+static gboolean
 gnt_entry_key_pressed(GntWidget *widget, const char *text)
 {
 	GntEntry *entry = GNT_ENTRY(widget);
@@ -629,6 +725,7 @@
 			destroy_suggest(entry);
 			complete_suggest(entry, text);
 			g_free(text);
+			update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 			entry_text_changed(entry);
 			return TRUE;
 		}
@@ -685,6 +782,7 @@
 				if (entry->ddown)
 					show_suggest_dropdown(entry);
 			}
+			update_kill_ring(entry, ENTRY_JAIL, NULL, 0);
 			entry_redraw(widget);
 			entry_text_changed(entry);
 			return TRUE;
@@ -695,6 +793,13 @@
 }
 
 static void
+jail_killring(GntEntryKillRing *kr)
+{
+	g_string_free(kr->buffer, TRUE);
+	g_free(kr);
+}
+
+static void
 gnt_entry_destroy(GntWidget *widget)
 {
 	GntEntry *entry = GNT_ENTRY(widget);
@@ -717,6 +822,8 @@
 	{
 		gnt_widget_destroy(entry->ddown->parent);
 	}
+
+	jail_killring(entry->killring);
 }
 
 static void
@@ -791,6 +898,8 @@
 				"\033" "d", NULL);
 	gnt_bindable_class_register_action(bindable, "transpose-chars", transpose_chars,
 				GNT_KEY_CTRL_T, NULL);
+	gnt_bindable_class_register_action(bindable, "yank", entry_yank,
+				GNT_KEY_CTRL_Y, NULL);
 	gnt_bindable_class_register_action(bindable, "suggest-show", suggest_show,
 				"\t", NULL);
 	gnt_bindable_class_register_action(bindable, "suggest-next", suggest_next,
@@ -808,6 +917,14 @@
 	GNTDEBUG;
 }
 
+static GntEntryKillRing *
+new_killring()
+{
+	GntEntryKillRing *kr = g_new0(GntEntryKillRing, 1);
+	kr->buffer = g_string_new(NULL);
+	return kr;
+}
+
 static void
 gnt_entry_init(GTypeInstance *instance, gpointer class)
 {
@@ -816,13 +933,14 @@
 
 	entry->flag = GNT_ENTRY_FLAG_ALL;
 	entry->max = 0;
-	
+
 	entry->histlength = 0;
 	entry->history = NULL;
 
 	entry->word = TRUE;
 	entry->always = FALSE;
 	entry->suggests = NULL;
+	entry->killring = new_killring();
 
 	GNT_WIDGET_SET_FLAGS(GNT_WIDGET(entry),
 			GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW | GNT_WIDGET_CAN_TAKE_FOCUS);
@@ -830,7 +948,7 @@
 
 	widget->priv.minw = 3;
 	widget->priv.minh = 1;
-	
+
 	GNTDEBUG;
 }
 
@@ -1021,7 +1139,7 @@
 
 	if (!text || !*text)
 		return;
-	
+
 	find = g_list_find_custom(entry->suggests, text, (GCompareFunc)g_utf8_collate);
 	if (find)
 		return;
--- a/finch/libgnt/gntentry.h	Fri Oct 26 09:44:00 2007 +0000
+++ b/finch/libgnt/gntentry.h	Fri Oct 26 13:31:26 2007 +0000
@@ -48,6 +48,7 @@
 typedef struct _GntEntry			GntEntry;
 typedef struct _GntEntryPriv		GntEntryPriv;
 typedef struct _GntEntryClass	GntEntryClass;
+typedef struct _GntEntryKillRing    GntEntryKillRing;
 
 typedef enum
 {
@@ -71,9 +72,9 @@
 	char *scroll;   /* Current scrolling position */
 	char *cursor;   /* Cursor location */
 	                /* 0 <= cursor - scroll < widget-width */
-	
+
 	size_t buffer;  /* Size of the buffer */
-	
+
 	int max;        /* 0 means infinite */
 	gboolean masked;
 
@@ -84,6 +85,7 @@
 	gboolean word;      /* Are the suggestions for only a word, or for the whole thing? */
 	gboolean always;    /* Should the list of suggestions show at all times, or only on tab-press? */
 	GntWidget *ddown;   /* The dropdown with the suggested list */
+	GntEntryKillRing *killring; /**< @since 2.3.0 */
 };
 
 struct _GntEntryClass