# HG changeset patch # User Eric Warmenhoven # Date 1001679354 0 # Node ID bdc74764245c0414f85a1c727a71a33fb0ff54d0 # Parent 05034cd0402bf89c5f821a0abb1b7981dde77ef2 [gaim-migrate @ 2398] Sean Egan's tab-completion patch. committer: Tailor Script diff -r 05034cd0402b -r bdc74764245c ChangeLog --- a/ChangeLog Fri Sep 28 09:33:38 2001 +0000 +++ b/ChangeLog Fri Sep 28 12:15:54 2001 +0000 @@ -8,6 +8,9 @@ SIGNALS) * Some GtkIMHtml improvements * Various bugfixes + * Nick Highlighting in chat + * Tab-completion for nicks in chat (thanks to Sean Egan) + * Large internal reworkings version 0.44 (09/20/2001): * More sane scaling of buddy icons (intelligently scale to diff -r 05034cd0402b -r bdc74764245c TODO --- a/TODO Fri Sep 28 09:33:38 2001 +0000 +++ b/TODO Fri Sep 28 12:15:54 2001 +0000 @@ -2,22 +2,18 @@ GPG Encryption of messages Have plugin_event use varargs instead of void* Separate core functions from UI stuff. - about.c, applet.[ch], away.c, conversation.c, convo.h, multi.c, - gtk*, prefs.c, prpl.c, sound.c, ticker.c + about.c, applet.[ch], away.c, buddy.c, conversation.c, convo.h, + dialogs.c, multi.c, gtk*, prefs.c, prpl.c, sound.c, ticker.c little to no work (mostly GTK) - gaimrc.c, html.c, proxy.[ch], prpl.h, server.c, util.c + gaimrc.c, html.c, list.c, proxy.[ch], prpl.h, server.c, util.c little to no work (mostly CORE) aim.c - need to redo main() completely - current main should be moved mostly to core - GTK main should connect to core browser.c - let the UI deal with this? little to no work. - buddy.c - need to split into buddy.c and list.c - - buddy.c handles add/remove/rename/alias buddies - - list.c handles drawing the buddy list for GTK buddy_chat.c - need to move out non-GTK functions. some work. - dialogs.c - need to move import/export out of here and into buddy.c gaim.h - need to separate into core.h and ui.h. idle.c - Need to figure out how to report idle times when there's more than one UI diff -r 05034cd0402b -r bdc74764245c src/buddy_chat.c --- a/src/buddy_chat.c Fri Sep 28 09:33:38 2001 +0000 +++ b/src/buddy_chat.c Fri Sep 28 12:15:54 2001 +0000 @@ -440,6 +440,163 @@ gtk_widget_show(invite); } +void tab_complete(struct conversation *c) +{ + int pos = GTK_EDITABLE(c->entry)->current_pos; + int start = pos; + int most_matched = -1; + char *entered, *partial = NULL; + char *text; + GList *matches = NULL; + GList *nicks = c->in_room; + + /* if there's nothing there just return */ + if (!start) + return; + + text = gtk_editable_get_chars(GTK_EDITABLE(c->entry), 0, pos); + + /* if we're at the end of ": " we need to move back 2 spaces */ + if (start >= 2 && text[start - 1] == ' ' && text[start - 2] == ':') + start -= 2; + + /* find the start of the word that we're tabbing */ + while (start > 0 && text[start - 1] != ' ') + start--; + + entered = text + start; + if (chat_options & OPT_CHAT_OLD_STYLE_TAB) { + if (strlen(entered) >= 2 && !strncmp(": ", entered + strlen(entered) - 2, 2)) + entered[strlen(entered) - 2] = 0; + } + + if (!strlen(entered)) { + g_free(text); + return; + } + + debug_printf("checking tab-completion for %s\n", entered); + + while (nicks) { + char *nick = nicks->data; + /* this checks to see if the current nick could be a completion */ + if (g_strncasecmp(nick, entered, strlen(entered))) { + if (nick[0] != '+' && nick[0] != '@') { + nicks = nicks->next; + continue; + } + if (g_strncasecmp(nick + 1, entered, strlen(entered))) { + if (nick[0] != '@' && nick[1] != '+') { + nicks = nicks->next; + continue; + } + if (g_strncasecmp(nick + 2, entered, strlen(entered))) { + nicks = nicks->next; + continue; + } + else + nick += 2; + } else + nick++; + } + /* if we're here, it's a possible completion */ + debug_printf("possible completion: %s\n", nick); + + /* if we're doing old-style, just fill in the completion */ + if (chat_options & OPT_CHAT_OLD_STYLE_TAB) { + gtk_editable_delete_text(GTK_EDITABLE(c->entry), start, pos); + if (strlen(nick) == strlen(entered)) { + nicks = nicks->next ? nicks->next : c->in_room; + nick = nicks->data; + if (*nick == '@') + nick++; + if (*nick == '+') + nick++; + } + + if (start == 0) { + char *tmp = g_strdup_printf("%s: ", nick); + int t = start; + gtk_editable_insert_text(GTK_EDITABLE(c->entry), tmp, strlen(tmp), &start); + if (t == start) { + t = start + strlen(tmp); + gtk_editable_set_position(GTK_EDITABLE(c->entry), t); + } + g_free(tmp); + } else { + int t = start; + gtk_editable_insert_text(GTK_EDITABLE(c->entry), nick, strlen(nick), &start); + if (t == start) { + t = start + strlen(nick); + gtk_editable_set_position(GTK_EDITABLE(c->entry), t); + } + } + g_free(text); + return; + } + + /* we're only here if we're doing new style */ + if (most_matched == -1) { + /* this will only get called once, since from now on most_matched is >= 0 */ + most_matched = strlen(nick); + partial = g_strdup(nick); + } else if (most_matched) { + while (g_strncasecmp(nick, partial, most_matched)) + most_matched--; + partial[most_matched] = 0; + } + matches = g_list_append(matches, nick); + + nicks = nicks->next; + } + /* we're only here if we're doing new style */ + + /* if there weren't any matches, return */ + if (!matches) { + /* if matches isn't set partials won't be either */ + g_free(text); + return; + } + + gtk_editable_delete_text(GTK_EDITABLE(c->entry), start, pos); + if (!matches->next) { + /* there was only one match. fill it in. */ + if (start == 0) { + char *tmp = g_strdup_printf("%s: ", (char *)matches->data); + int t = start; + gtk_editable_insert_text(GTK_EDITABLE(c->entry), tmp, strlen(tmp), &start); + if (t == start) { + t = start + strlen(tmp); + gtk_editable_set_position(GTK_EDITABLE(c->entry), t); + } + g_free(tmp); + } else { + gtk_editable_insert_text(GTK_EDITABLE(c->entry), matches->data, strlen(matches->data), &start); + } + matches = g_list_remove(matches, matches->data); + } else { + /* there were lots of matches, fill in as much as possible and display all of them */ + char *addthis = g_malloc0(1); + int t = start; + while (matches) { + char *tmp = addthis; + addthis = g_strconcat(tmp, matches->data, " ", NULL); + g_free(tmp); + matches = g_list_remove(matches, matches->data); + } + write_to_conv(c, addthis, WFLAG_NOLOG, NULL, time(NULL)); + gtk_editable_insert_text(GTK_EDITABLE(c->entry), partial, strlen(partial), &start); + if (t == start) { + t = start + strlen(partial); + gtk_editable_set_position(GTK_EDITABLE(c->entry), t); + } + g_free(addthis); + } + + g_free(text); + g_free(partial); +} + gboolean meify(char *message) { /* read /me-ify : if the message (post-HTML) starts with /me, remove diff -r 05034cd0402b -r bdc74764245c src/conversation.c --- a/src/conversation.c Fri Sep 28 09:33:38 2001 +0000 +++ b/src/conversation.c Fri Sep 28 12:15:54 2001 +0000 @@ -755,6 +755,9 @@ gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event"); } } + } else if ((event->keyval == GDK_Tab) && c->is_chat && (chat_options & OPT_CHAT_TAB_COMPLETE)) { + tab_complete(c); + gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event"); } else if (((!c->is_chat && (im_options & OPT_IM_ONE_WINDOW)) || (c->is_chat && (chat_options & OPT_CHAT_ONE_WINDOW))) && (event->state & GDK_MOD1_MASK) && isdigit(event->keyval) && (event->keyval > '0')) { @@ -1396,7 +1399,7 @@ c->history = g_string_append(c->history, "
\n"); } - if ((logging_options & OPT_LOG_ALL) || find_log_info(c->name)) { + if (!(flags & WFLAG_NOLOG) && ((logging_options & OPT_LOG_ALL) || find_log_info(c->name))) { char *t1; char nm[256]; @@ -1422,7 +1425,9 @@ g_free(t1); } } - + } else if (flags & WFLAG_NOLOG) { + g_snprintf(buf, BUF_LONG, "%s
", what); + gtk_imhtml_append_text(GTK_IMHTML(c->text), buf, 0); } else { if (flags & WFLAG_WHISPER) { /* if we're whispering, it's not an autoresponse */ @@ -1499,7 +1504,7 @@ g_free(t2); } - if ((logging_options & OPT_LOG_ALL) || find_log_info(c->name)) { + if (!(flags & WFLAG_NOLOG) && ((logging_options & OPT_LOG_ALL) || find_log_info(c->name))) { char *t1, *t2; char *nm = g_malloc(256); if (c->is_chat) diff -r 05034cd0402b -r bdc74764245c src/convo.h --- a/src/convo.h Fri Sep 28 09:33:38 2001 +0000 +++ b/src/convo.h Fri Sep 28 12:15:54 2001 +0000 @@ -41,6 +41,7 @@ extern void ignore_callback(GtkWidget *, struct conversation *); extern void whisper_callback(GtkWidget *, struct conversation *); extern void invite_callback(GtkWidget *, struct conversation *); +extern void tab_complete(struct conversation *c); /* now IM */ extern void warn_callback(GtkWidget *, struct conversation *); diff -r 05034cd0402b -r bdc74764245c src/gaim.h --- a/src/gaim.h Fri Sep 28 09:33:38 2001 +0000 +++ b/src/gaim.h Fri Sep 28 12:15:54 2001 +0000 @@ -70,6 +70,7 @@ #define WFLAG_FILERECV 0x10 #define WFLAG_SYSTEM 0x20 #define WFLAG_NICK 0x40 +#define WFLAG_NOLOG 0x80 #define AUTO_RESPONSE "<AUTO-REPLY> : " @@ -528,6 +529,8 @@ #define OPT_CHAT_POPUP 0x00000010 #define OPT_CHAT_SIDE_TAB 0x00000020 #define OPT_CHAT_BR_TAB 0x00000040 +#define OPT_CHAT_TAB_COMPLETE 0x00000080 +#define OPT_CHAT_OLD_STYLE_TAB 0x00000100 extern guint font_options; #define OPT_FONT_BOLD 0x00000001 diff -r 05034cd0402b -r bdc74764245c src/prefs.c --- a/src/prefs.c Fri Sep 28 09:33:38 2001 +0000 +++ b/src/prefs.c Fri Sep 28 12:15:54 2001 +0000 @@ -984,6 +984,8 @@ GtkWidget *button; GtkWidget *hbox2; GtkWidget *vbox3; + GtkWidget *tab; + GtkWidget *old; parent = prefdialog->parent; gtk_widget_destroy(prefdialog); @@ -1086,6 +1088,29 @@ opt = tab_radio(_("Right"), OPT_CHAT_SIDE_TAB | OPT_CHAT_BR_TAB | 1, vbox3, opt); gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(toggle_sensitive), opt); + frame = gtk_frame_new(_("Tab Completion")); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5); + gtk_widget_show(frame); + + hbox = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(frame), hbox); + gtk_widget_show(hbox); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5); + gtk_widget_show(vbox); + + tab = gaim_button(_("Tab-Complete Nicks"), &chat_options, OPT_CHAT_TAB_COMPLETE, vbox); + + vbox = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 5); + gtk_widget_show(vbox); + + old = gaim_button(_("Old-Style Tab Completion"), &chat_options, OPT_CHAT_OLD_STYLE_TAB, vbox); + if (!(chat_options & OPT_CHAT_TAB_COMPLETE)) + gtk_widget_set_sensitive(GTK_WIDGET(old), FALSE); + gtk_signal_connect(GTK_OBJECT(tab), "clicked", GTK_SIGNAL_FUNC(toggle_sensitive), old); + gtk_widget_show(prefdialog); }