comparison pidgin/gtkconv.c @ 22805:e1052f4b0254

Modified patch from Andrei Mozzhuhin to fix tab-completion when non-ascii characters are involved. Closes #5653.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Thu, 01 May 2008 22:42:21 +0000
parents 4040c4ee1f44
children 6079335eb01c fdf60a5c2f66
comparison
equal deleted inserted replaced
22804:1de2fa8be76b 22805:e1052f4b0254
3978 g_object_unref(pixbuf); 3978 g_object_unref(pixbuf);
3979 g_free(alias_key); 3979 g_free(alias_key);
3980 } 3980 }
3981 3981
3982 static void 3982 static void
3983 tab_complete_process_item(int *most_matched, char *entered, char **partial, char *nick_partial, 3983 tab_complete_process_item(int *most_matched, char *entered, gsize entered_bytes, char **partial, char *nick_partial,
3984 GList **matches, gboolean command, char *name) 3984 GList **matches, gboolean command, char *name)
3985 { 3985 {
3986 strncpy(nick_partial, name, strlen(entered)); 3986 memcpy(nick_partial, name, entered_bytes);
3987 nick_partial[strlen(entered)] = '\0';
3988 if (purple_utf8_strcasecmp(nick_partial, entered)) 3987 if (purple_utf8_strcasecmp(nick_partial, entered))
3989 return; 3988 return;
3990 3989
3991 /* if we're here, it's a possible completion */ 3990 /* if we're here, it's a possible completion */
3992 3991
4027 char *text; 4026 char *text;
4028 char *nick_partial; 4027 char *nick_partial;
4029 const char *prefix; 4028 const char *prefix;
4030 GList *matches = NULL; 4029 GList *matches = NULL;
4031 gboolean command = FALSE; 4030 gboolean command = FALSE;
4031 gsize entered_bytes = 0;
4032 4032
4033 gtkconv = PIDGIN_CONVERSATION(conv); 4033 gtkconv = PIDGIN_CONVERSATION(conv);
4034 4034
4035 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, &start_buffer); 4035 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, &start_buffer);
4036 gtk_text_buffer_get_iter_at_mark(gtkconv->entry_buffer, &cursor, 4036 gtk_text_buffer_get_iter_at_mark(gtkconv->entry_buffer, &cursor,
4046 &cursor, FALSE); 4046 &cursor, FALSE);
4047 4047
4048 /* if we're at the end of ": " we need to move back 2 spaces */ 4048 /* if we're at the end of ": " we need to move back 2 spaces */
4049 start = strlen(text) - 1; 4049 start = strlen(text) - 1;
4050 4050
4051 if (strlen(text) >= 2 && !strncmp(&text[start-1], ": ", 2)) { 4051 if (start >= 1 && !strncmp(&text[start-1], ": ", 2)) {
4052 gtk_text_iter_backward_chars(&word_start, 2); 4052 gtk_text_iter_backward_chars(&word_start, 2);
4053 start-=2; 4053 }
4054 } 4054
4055 4055 /* find the start of the word that we're tabbing.
4056 /* find the start of the word that we're tabbing */ 4056 * Using gtk_text_iter_backward_word_start won't work, because a nick can contain
4057 while (start >= 0 && text[start] != ' ') { 4057 * characters (e.g. '.', '/' etc.) that Pango may think are word separators. */
4058 gtk_text_iter_backward_char(&word_start); 4058 while (gtk_text_iter_backward_char(&word_start)) {
4059 start--; 4059 if (gtk_text_iter_get_char(&word_start) == ' ') {
4060 /* Reached the whitespace before the start of the word. Move forward once */
4061 gtk_text_iter_forward_char(&word_start);
4062 break;
4063 }
4060 } 4064 }
4061 4065
4062 prefix = pidgin_get_cmd_prefix(); 4066 prefix = pidgin_get_cmd_prefix();
4063 if (start == -1 && (strlen(text) >= strlen(prefix)) && !strncmp(text, prefix, strlen(prefix))) { 4067 if (gtk_text_iter_get_offset(&word_start) == 0 &&
4068 (strlen(text) >= strlen(prefix)) && !strncmp(text, prefix, strlen(prefix))) {
4064 command = TRUE; 4069 command = TRUE;
4065 gtk_text_iter_forward_chars(&word_start, strlen(prefix)); 4070 gtk_text_iter_forward_chars(&word_start, strlen(prefix));
4066 } 4071 }
4067 4072
4068 g_free(text); 4073 g_free(text);
4069 4074
4070 entered = gtk_text_buffer_get_text(gtkconv->entry_buffer, &word_start, 4075 entered = gtk_text_buffer_get_text(gtkconv->entry_buffer, &word_start,
4071 &cursor, FALSE); 4076 &cursor, FALSE);
4077 entered_bytes = strlen(entered);
4072 4078
4073 if (!g_utf8_strlen(entered, -1)) { 4079 if (!g_utf8_strlen(entered, -1)) {
4074 g_free(entered); 4080 g_free(entered);
4075 return (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) ? TRUE : FALSE; 4081 return (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) ? TRUE : FALSE;
4076 } 4082 }
4077 4083
4078 nick_partial = g_malloc(strlen(entered)+1); 4084 nick_partial = g_malloc0(entered_bytes + 1);
4079 4085
4080 if (command) { 4086 if (command) {
4081 GList *list = purple_cmd_list(conv); 4087 GList *list = purple_cmd_list(conv);
4082 GList *l; 4088 GList *l;
4083 4089
4084 /* Commands */ 4090 /* Commands */
4085 for (l = list; l != NULL; l = l->next) { 4091 for (l = list; l != NULL; l = l->next) {
4086 tab_complete_process_item(&most_matched, entered, &partial, nick_partial, 4092 tab_complete_process_item(&most_matched, entered, entered_bytes, &partial, nick_partial,
4087 &matches, TRUE, l->data); 4093 &matches, TRUE, l->data);
4088 } 4094 }
4089 g_list_free(list); 4095 g_list_free(list);
4090 } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { 4096 } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
4091 PurpleConvChat *chat = PURPLE_CONV_CHAT(conv); 4097 PurpleConvChat *chat = PURPLE_CONV_CHAT(conv);
4094 GtkTreeIter iter; 4100 GtkTreeIter iter;
4095 int f; 4101 int f;
4096 4102
4097 /* Users */ 4103 /* Users */
4098 for (; l != NULL; l = l->next) { 4104 for (; l != NULL; l = l->next) {
4099 tab_complete_process_item(&most_matched, entered, &partial, nick_partial, 4105 tab_complete_process_item(&most_matched, entered, entered_bytes, &partial, nick_partial,
4100 &matches, TRUE, ((PurpleConvChatBuddy *)l->data)->name); 4106 &matches, TRUE, ((PurpleConvChatBuddy *)l->data)->name);
4101 } 4107 }
4102 4108
4103 4109
4104 /* Aliases */ 4110 /* Aliases */
4112 CHAT_USERS_NAME_COLUMN, &name, 4118 CHAT_USERS_NAME_COLUMN, &name,
4113 CHAT_USERS_ALIAS_COLUMN, &alias, 4119 CHAT_USERS_ALIAS_COLUMN, &alias,
4114 -1); 4120 -1);
4115 4121
4116 if (name && alias && strcmp(name, alias)) 4122 if (name && alias && strcmp(name, alias))
4117 tab_complete_process_item(&most_matched, entered, &partial, nick_partial, 4123 tab_complete_process_item(&most_matched, entered, entered_bytes, &partial, nick_partial,
4118 &matches, FALSE, alias); 4124 &matches, FALSE, alias);
4119 g_free(name); 4125 g_free(name);
4120 g_free(alias); 4126 g_free(alias);
4121 4127
4122 f = gtk_tree_model_iter_next(model, &iter); 4128 f = gtk_tree_model_iter_next(model, &iter);