Exemplo n.º 1
0
static int
key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
							struct session *sess)
{
	int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, prefix_len, skip_len = 0;
	gboolean is_nick = FALSE, is_cmd = FALSE, found = FALSE, has_nick_prefix = FALSE;
	char ent[CHANLEN], *postfix = NULL, *result, *ch;
	GList *list = NULL, *tmp_list = NULL;
	const char *text;
	GCompletion *gcomp = NULL;
	GString *buf;

	/* force the IM Context to reset */
	SPELL_ENTRY_SET_EDITABLE (t, FALSE);
	SPELL_ENTRY_SET_EDITABLE (t, TRUE);

	text = SPELL_ENTRY_GET_TEXT (t);
	if (text[0] == 0)
		return 1;

	len = g_utf8_strlen (text, -1); /* must be null terminated */

	cursor_pos = SPELL_ENTRY_GET_POS (t);

	/* handle "nick: " or "nick " or "#channel "*/
	ch = g_utf8_find_prev_char(text, g_utf8_offset_to_pointer(text,cursor_pos));
	if (ch && ch[0] == ' ')
	{
		skip_len++;
		ch = g_utf8_find_prev_char(text, ch);
		if (!ch)
			return 2;

		cursor_pos = g_utf8_pointer_to_offset(text, ch);
		if (cursor_pos && (g_utf8_get_char_validated(ch, -1) == ':' || 
					g_utf8_get_char_validated(ch, -1) == ',' ||
					g_utf8_get_char_validated (ch, -1) == g_utf8_get_char_validated (prefs.hex_completion_suffix, -1)))
		{
			skip_len++;
		}
		else
			cursor_pos = g_utf8_pointer_to_offset(text, g_utf8_offset_to_pointer(ch, 1));
	}

	comp = skip_len;
	
	/* store the text following the cursor for reinsertion later */
	if ((cursor_pos + skip_len) < len)
		postfix = g_utf8_offset_to_pointer(text, cursor_pos + skip_len);

	for (ent_start = cursor_pos; ; --ent_start)
	{
		if (ent_start == 0)
			break;
		ch = g_utf8_offset_to_pointer(text, ent_start - 1);
		if (ch && ch[0] == ' ')
			break;
	}

	if (ent_start == 0 && text[0] == prefs.hex_input_command_char[0])
	{
		ent_start++;
		is_cmd = TRUE;
	}
	else if (strchr (sess->server->chantypes, text[ent_start]) == NULL)
	{
		is_nick = TRUE;
		if (strchr (sess->server->nick_prefixes, text[ent_start]) != NULL)
		{
			if (ent_start == 0)
				has_nick_prefix = TRUE;
			ent_start++;
		}
	}

	prefix_len = ent_start;
	elen = cursor_pos - ent_start;

	g_utf8_strncpy (ent, g_utf8_offset_to_pointer (text, prefix_len), elen);
	
	if (sess->type == SESS_DIALOG && is_nick)
	{
		/* tab in a dialog completes the other person's name */
		if (rfc_ncasecmp (sess->channel, ent, elen) == 0)
		{
			result =  sess->channel;
			is_nick = FALSE;
		}
		else
			return 2;
	}
	else
	{
		if (is_nick)
		{
			gcomp = g_completion_new((GCompletionFunc)gcomp_nick_func);
			tmp_list = userlist_double_list(sess); /* create a temp list so we can free the memory */
			if (prefs.hex_completion_sort == 1)	/* sort in last-talk order? */
				tmp_list = g_list_sort (tmp_list, (void *)talked_recent_cmp);
		}
		else
		{
			gcomp = g_completion_new (NULL);
			if (is_cmd)
			{
				tmp_list = cmdlist_double_list (command_list);
				for(i = 0; xc_cmds[i].name != NULL ; i++)
				{
					tmp_list = g_list_prepend (tmp_list, xc_cmds[i].name);
				}
				tmp_list = plugin_command_list(tmp_list);
			}
			else
				tmp_list = chanlist_double_list (sess_list);
		}
		tmp_list = g_list_reverse(tmp_list); /* make the comp entries turn up in the right order */
		g_completion_set_compare (gcomp, (GCompletionStrncmpFunc)rfc_ncasecmp);
		if (tmp_list)
		{
			g_completion_add_items (gcomp, tmp_list);
			g_list_free (tmp_list);
		}

		if (comp && !(rfc_ncasecmp(old_gcomp.data, ent, old_gcomp.elen) == 0))
		{
			key_action_tab_clean ();
			comp = 0;
		}
	
		list = g_completion_complete_utf8 (gcomp, comp ? old_gcomp.data : ent, &result);
		
		if (result == NULL) /* No matches found */
		{
			g_completion_free(gcomp);
			return 2;
		}

		if (comp) /* existing completion */
		{
			while(list) /* find the current entry */
			{
				if(rfc_ncasecmp(list->data, ent, elen) == 0)
				{
					found = TRUE;
					break;
				}
				list = list->next;
			}

			if (found)
			{
				if (!(d1 && d1[0])) /* not holding down shift */
				{
					if (g_list_next(list) == NULL)
						list = g_list_first(list);
					else
						list = g_list_next(list);
				}
				else
				{
					if (g_list_previous(list) == NULL)
						list = g_list_last(list);
					else
						list = g_list_previous(list);
				}
				g_free(result);
				result = (char*)list->data;
			}
			else
			{
				g_free(result);
				g_completion_free(gcomp);
				return 2;
			}
		}
		else
		{
			strcpy(old_gcomp.data, ent);
			old_gcomp.elen = elen;

			/* Get the first nick and put out the data for future nickcompletes */
			if (prefs.hex_completion_amount > 0 && g_list_length (list) <= (guint) prefs.hex_completion_amount)
			{
				g_free(result);
				result = (char*)list->data;
			}
			else
			{
				/* bash style completion */
				if (g_list_next(list) != NULL)
				{
					buf = g_string_sized_new (MAX(COMP_BUF, len + NICKLEN));
					if (strlen (result) > elen) /* the largest common prefix is larger than nick, change the data */
					{
						if (prefix_len)
							g_string_append_len (buf, text, offset_to_len (text, prefix_len));
						g_string_append (buf, result);
						cursor_pos = buf->len;
						g_free(result);
						if (postfix)
						{
							g_string_append_c (buf, ' ');
							g_string_append (buf, postfix);
						}
						SPELL_ENTRY_SET_TEXT (t, buf->str);
						SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos));
						g_string_erase (buf, 0, -1);
					}
					else
						g_free(result);

					while (list)
					{
						len = buf->len;
						elen = strlen (list->data);	/* next item to add */
						if (len + elen + 2 >= COMP_BUF) /* +2 is space + null */
						{
							PrintText (sess, buf->str);
							g_string_erase (buf, 0, -1);
						}
						g_string_append (buf, (char*)list->data);
						g_string_append_c (buf, ' ');
						list = list->next;
					}
					PrintText (sess, buf->str);
					g_completion_free(gcomp);
					g_string_free (buf, TRUE);
					return 2;
				}
				/* Only one matching entry */
				g_free(result);
				result = list->data;
			}
		}
	}
	
	if(result)
	{
		buf = g_string_sized_new (len + NICKLEN);
		if (prefix_len)
			g_string_append_len (buf, text, offset_to_len (text, prefix_len));
		g_string_append (buf, result);
		if((!prefix_len || has_nick_prefix) && is_nick && prefs.hex_completion_suffix[0] != '\0')
			g_string_append_unichar (buf, g_utf8_get_char_validated (prefs.hex_completion_suffix, -1));
		g_string_append_c (buf, ' ');
		cursor_pos = buf->len;
		if (postfix)
			g_string_append (buf, postfix);
		SPELL_ENTRY_SET_TEXT (t, buf->str);
		SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, cursor_pos));
		g_string_free (buf, TRUE);
	}
	if (gcomp)
		g_completion_free(gcomp);
	return 2;
}
Exemplo n.º 2
0
Arquivo: fkeys.c Projeto: n2i/xvnkb
static int
key_action_tab_comp (GtkWidget *t, GdkEventKey *entry, char *d1, char *d2,
							struct session *sess)
{
	int len = 0, elen = 0, i = 0, cursor_pos, ent_start = 0, comp = 0, found = 0,
	    prefix_len, skip_len = 0, is_nick, is_cmd = 0;
	char buf[COMP_BUF], ent[CHANLEN], *postfix = NULL, *result, *ch;
	GList *list = NULL, *tmp_list = NULL;
	const char *text;
	GCompletion *gcomp = NULL;

	/* force the IM Context to reset */
	SPELL_ENTRY_SET_EDITABLE (t, FALSE);
	SPELL_ENTRY_SET_EDITABLE (t, TRUE);

	text = SPELL_ENTRY_GET_TEXT (t);
	if (text[0] == 0)
		return 1;

	len = g_utf8_strlen (text, -1); /* must be null terminated */

	cursor_pos = SPELL_ENTRY_GET_POS (t);

	buf[0] = 0; /* make sure we don't get garbage in the buffer */

	/* handle "nick: " or "nick " or "#channel "*/
	ch = g_utf8_find_prev_char(text, g_utf8_offset_to_pointer(text,cursor_pos));
	if (ch && ch[0] == ' ')
	{
		skip_len++;
		ch = g_utf8_find_prev_char(text, ch);
		if (!ch)
			return 2;

		cursor_pos = g_utf8_pointer_to_offset(text, ch);
		if (cursor_pos && (g_utf8_get_char_validated(ch, -1) == ':' || 
					g_utf8_get_char_validated(ch, -1) == ',' ||
					g_utf8_get_char_validated(ch, -1) == prefs.nick_suffix[0]))
		{
			skip_len++;
		}
		else
			cursor_pos = g_utf8_pointer_to_offset(text, g_utf8_offset_to_pointer(ch, 1));
	}

	comp = skip_len;
	
	/* store the text following the cursor for reinsertion later */
	if ((cursor_pos + skip_len) < len)
		postfix = g_utf8_offset_to_pointer(text, cursor_pos + skip_len);

	for (ent_start = cursor_pos; ; --ent_start)
	{
		if (ent_start == 0)
			break;
		ch = g_utf8_offset_to_pointer(text, ent_start - 1);
		if (ch && ch[0] == ' ')
			break;
	}

	if (ent_start == 0 && text[0] == prefs.cmdchar[0])
	{
		ent_start++;
		is_cmd = 1;
	}
	
	prefix_len = ent_start;
	elen = cursor_pos - ent_start;

	g_utf8_strncpy (ent, g_utf8_offset_to_pointer (text, prefix_len), elen);

	is_nick = (ent[0] == '#' || ent[0] == '&' || is_cmd) ? 0 : 1;
	
	if (sess->type == SESS_DIALOG && is_nick)
	{
		/* tab in a dialog completes the other person's name */
		if (rfc_ncasecmp (sess->channel, ent, elen) == 0)
		{
			result =  sess->channel;
			is_nick = 0;
		}
		else
			return 2;
	}
	else
	{
		if (is_nick)
		{
			gcomp = g_completion_new((GCompletionFunc)gcomp_nick_func);
			tmp_list = userlist_double_list(sess); /* create a temp list so we can free the memory */
			if (prefs.completion_sort == 1)	/* sort in last-talk order? */
				tmp_list = g_list_sort (tmp_list, (void *)talked_recent_cmp);
		}
		else
		{
			gcomp = g_completion_new (NULL);
			if (is_cmd)
			{
				tmp_list = cmdlist_double_list (command_list);
				for(i = 0; xc_cmds[i].name != NULL ; i++)
				{
					tmp_list = g_list_prepend (tmp_list, xc_cmds[i].name);
				}
				tmp_list = plugin_command_list(tmp_list);
			}
			else
				tmp_list = chanlist_double_list (sess_list);
		}
		tmp_list = g_list_reverse(tmp_list); /* make the comp entries turn up in the right order */
		g_completion_set_compare (gcomp, (GCompletionStrncmpFunc)rfc_ncasecmp);
		if (tmp_list)
		{
			g_completion_add_items (gcomp, tmp_list);
			g_list_free (tmp_list);
		}

		if (comp && !(rfc_ncasecmp(old_gcomp.data, ent, old_gcomp.elen) == 0))
		{
			key_action_tab_clean ();
			comp = 0;
		}
	
#if GLIB_CHECK_VERSION(2,4,0)
		list = g_completion_complete_utf8 (gcomp, comp ? old_gcomp.data : ent, &result);
#else
		list = g_completion_complete (gcomp, comp ? old_gcomp.data : ent, &result);
#endif
		
		if (result == NULL) /* No matches found */
		{
			g_completion_free(gcomp);
			return 2;
		}

		if (comp) /* existing completion */
		{
			while(list) /* find the current entry */
			{
				if(rfc_ncasecmp(list->data, ent, elen) == 0)
				{
					found = 1;
					break;
				}
				list = list->next;
			}

			if (found)
			{
				if (!(d1 && d1[0])) /* not holding down shift */
				{
					if (g_list_next(list) == NULL)
						list = g_list_first(list);
					else
						list = g_list_next(list);
				}
				else
				{
					if (g_list_previous(list) == NULL)
						list = g_list_last(list);
					else
						list = g_list_previous(list);
				}
				g_free(result);
				result = (char*)list->data;
			}
			else
			{
				g_free(result);
				g_completion_free(gcomp);
				return 2;
			}
		}
		else
		{
			strcpy(old_gcomp.data, ent);
			old_gcomp.elen = elen;

			/* Get the first nick and put out the data for future nickcompletes */
			if (prefs.completion_amount && g_list_length (list) <= prefs.completion_amount)
			{
				g_free(result);
				result = (char*)list->data;
			}
			else
			{
				/* bash style completion */
				if (g_list_next(list) != NULL)
				{
					if (strlen (result) > elen) /* the largest common prefix is larger than nick, change the data */
					{
						if (prefix_len)
							g_utf8_strncpy (buf, text, prefix_len);
						strncat (buf, result, COMP_BUF - prefix_len);
						cursor_pos = strlen (buf);
						g_free(result);
#if !GLIB_CHECK_VERSION(2,4,0)
						g_utf8_validate (buf, -1, (const gchar **)&result);
						(*result) = 0;
#endif
						if (postfix)
						{
							strcat (buf, " ");
							strncat (buf, postfix, COMP_BUF - cursor_pos -1);
						}
						SPELL_ENTRY_SET_TEXT (t, buf);
						SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos));
						buf[0] = 0;
					}
					else
						g_free(result);
					while (list)
					{
						len = strlen (buf);	/* current buffer */
						elen = strlen (list->data);	/* next item to add */
						if (len + elen + 2 >= COMP_BUF) /* +2 is space + null */
						{
							PrintText (sess, buf);
							buf[0] = 0;
							len = 0;
						}
						strcpy (buf + len, (char *) list->data);
						strcpy (buf + len + elen, " ");
						list = list->next;
					}
					PrintText (sess, buf);
					g_completion_free(gcomp);
					return 2;
				}
				/* Only one matching entry */
				g_free(result);
				result = list->data;
			}
		}
	}
	
	if(result)
	{
		if (prefix_len)
			g_utf8_strncpy(buf, text, prefix_len);
		strncat (buf, result, COMP_BUF - (prefix_len + 3)); /* make sure nicksuffix and space fits */
		if(!prefix_len && is_nick)
			strcat (buf, &prefs.nick_suffix[0]);
		strcat (buf, " ");
		cursor_pos = strlen (buf);
		if (postfix)
			strncat (buf, postfix, COMP_BUF - cursor_pos - 2);
		SPELL_ENTRY_SET_TEXT (t, buf);
		SPELL_ENTRY_SET_POS (t, g_utf8_pointer_to_offset(buf, buf + cursor_pos));
	}
	if (gcomp)
		g_completion_free(gcomp);
	return 2;
}