Added history and tab-completion based on the history contents. Fixed

potential segmentation fault if key symbol translation fails.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@650 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
shaper
2002-03-14 16:45:26 +00:00
parent 40e0623806
commit 93bcb0bbdb
5 changed files with 244 additions and 7 deletions
+3 -2
View File
@@ -1,5 +1,5 @@
#
# $Id: Makefile.am,v 1.4 2001/08/18 02:34:06 mdb Exp $
# $Id: Makefile.am,v 1.5 2002/03/14 16:45:26 shaper Exp $
bin_PROGRAMS = lookuplet
@@ -9,7 +9,8 @@ lookuplet_SOURCES = \
querybox.c \
preferences.c \
binding.c \
keysym-util.c
keysym-util.c \
history.c
INCLUDES = \
-I. \
+118
View File
@@ -0,0 +1,118 @@
/**
* $Id: history.c,v 1.1 2002/03/14 16:45:26 shaper Exp $
*
* lookuplet - a utility for quickly looking up information
* Copyright (C) 2001 Michael Bayne
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <gnome.h>
#include "history.h"
/* the array of historical entries */
static gchar** _history;
/* the last entry index retrieved */
static int _ridx = 0;
/* the insertion index for new history items */
static int _iidx = 0;
/* the number of entries saved in the text entry history */
#define HISTORY_COUNT (10)
void
lk_init_history (void)
{
/* allocate and initialize the array of history entries */
size_t size = sizeof(gchar*) * HISTORY_COUNT;
_history = g_malloc(size);
memset(_history, (int)NULL, size);
}
const gchar*
lk_get_history (gboolean next)
{
int actidx;
/* make sure the array is available */
if (_history == NULL) {
return NULL;
}
/* determine the sought-after index */
actidx = _ridx + ((next) ? -1 : 1);
/* make sure the index is valid and an entry exists */
if (actidx < 0 || actidx >= HISTORY_COUNT || _history[actidx] == NULL) {
return NULL;
}
/* update the retrieved index */
_ridx = actidx;
return _history[actidx];
}
const gchar*
lk_get_history_expand (const gchar* entry)
{
int i, len;
if (_history == NULL || entry == NULL) {
return NULL;
}
len = strlen(entry);
for (i = _iidx; i >= 0; i--) {
gchar* str = _history[i];
if (str != NULL && !g_strncasecmp(str, entry, len)) {
/* update the retrieved index for potential subsequent retrievals */
_ridx = i;
return str;
}
}
return NULL;
}
void
lk_add_history (const gchar* entry)
{
/* make sure the array is available and the entry is valid */
if (_history == NULL || entry == NULL) {
return;
}
/* if there's no space remaining, shift off the oldest entry */
if (_iidx == HISTORY_COUNT - 1 && _history[_iidx] != NULL) {
g_free(_history[0]);
memmove(_history, _history + 1, sizeof(gchar*) * (HISTORY_COUNT - 1));
_history[_iidx] = NULL;
}
/* remember the new entry */
_history[_iidx] = g_strdup(entry);
/* increment the insertion and retrieved index */
if (_iidx < HISTORY_COUNT - 1) {
_iidx++;
_ridx = _iidx;
} else {
_ridx = HISTORY_COUNT;
}
}
+59
View File
@@ -0,0 +1,59 @@
/**
* $Id: history.h,v 1.1 2002/03/14 16:45:26 shaper Exp $
*
* lookuplet - a utility for quickly looking up information
* Copyright (C) 2001 Michael Bayne
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _HISTORY_H_
#define _HISTORY_H_
#include <glib.h>
/**
* Initializes the history storage.
*/
void
lk_init_history (void);
/**
* Returns the next history entry if next is true, else returns the
* previous history entry.
*/
const gchar*
lk_get_history (gboolean next);
/**
* Returns the most recent history entry that matches the specified
* partial entry text, or NULL if there are no matches. String
* comparisons are case-insensitive as this is intended for use in
* effecting auto-completion of sloppily-inputted partial entries. If a
* matching entry is found, the current history item index is set to point
* to that entry such that subsequent history entry retrievals will
* automagically pick up from that point.
*/
const gchar*
lk_get_history_expand (const gchar* entry);
/**
* Adds an entry to the history and resets the current history item index
* to point to the new entry.
*/
void
lk_add_history (const gchar* entry);
#endif /* _HISTORY_H_ */
+2 -2
View File
@@ -1,5 +1,5 @@
/**
* $Id: lookuplet.c,v 1.6 2001/08/18 02:34:06 mdb Exp $
* $Id: lookuplet.c,v 1.7 2002/03/14 16:45:26 shaper Exp $
*
* lookuplet - a utility for quickly looking up information
* Copyright (C) 2001 Michael Bayne
@@ -84,7 +84,7 @@ main (int argc, char** argv)
#endif
if (applet_mode) {
/* intialize; this will basically set up the applet, corba and
/* initialize; this will basically set up the applet, corba and
call gnome_init() */
applet_widget_init(PACKAGE, VERSION, argc, argv, NULL, 0, NULL);
+62 -3
View File
@@ -1,5 +1,5 @@
/**
* $Id: querybox.c,v 1.8 2001/08/21 18:46:10 mdb Exp $
* $Id: querybox.c,v 1.9 2002/03/14 16:45:26 shaper Exp $
*
* lookuplet - a utility for quickly looking up information
* Copyright (C) 2001 Michael Bayne
@@ -27,16 +27,25 @@
#include "binding.h"
#include "launcher.h"
#include "history.h"
#include "keysym-util.h"
#include "preferences.h"
#include "lookuplet.h"
#include "querybox.h"
/* the query text entry field */
static GtkWidget* _query;
/* used by url_p */
#define MATCH_PREFIX(text, prefix) !strncmp(text, prefix, sizeof(prefix)-1)
/* key codes for navigating the entry history */
#define NEXT_HISTORY_KEY (GDK_Up)
#define PREVIOUS_HISTORY_KEY (GDK_Down)
/* key code for auto-completion of a partial entry */
#define AUTO_COMPLETE_KEY (GDK_Tab)
/**
* A very primitive function to try to determine if the selection is a URL
* of some sort.
@@ -95,6 +104,41 @@ selection_received (GtkWidget* widget, GtkSelectionData* selection_data,
}
}
static gint
handle_special_keys (GtkWidget* widget, GdkEventKey* ek)
{
const gchar* entry = NULL;
switch (ek->keyval) {
case NEXT_HISTORY_KEY:
case PREVIOUS_HISTORY_KEY:
/* retrieve the sought-after historical entry */
entry = lk_get_history(ek->keyval == NEXT_HISTORY_KEY);
break;
case AUTO_COMPLETE_KEY: {
/* get the terms from the query box */
gchar* text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
/* seek an expanded historical entry for the current text */
entry = lk_get_history_expand(text);
}
break;
}
/* if we've an entry, fill it in and we're done */
if (entry != NULL) {
/* place the entry in the text field */
gtk_entry_set_text(GTK_ENTRY(widget), entry);
/* select the text in the entry so that it can be easily replaced */
gtk_editable_select_region(GTK_EDITABLE(_query), 0, strlen(entry));
return TRUE;
}
return FALSE;
}
static gint
key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
{
@@ -103,6 +147,11 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
gint handled = FALSE, i;
gchar* keystr;
/* handle special keystrokes such as history and auto-complete */
if (handle_special_keys(widget, ek)) {
return TRUE;
}
/* ignore plain or shifted keystrokes */
if (ek->state <= 1) {
return FALSE;
@@ -110,6 +159,9 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
/* otherwise convert the key combo to a name and look it up */
keystr = convert_keysym_state_to_string(ek->keyval, ek->state);
if (keystr == NULL) {
return FALSE;
}
bindings = lk_prefs_get_bindings();
for (i = 0; i < bindings->len; i++) {
@@ -118,9 +170,11 @@ key_pressed (GtkWidget* widget, GdkEvent* event, gpointer callback_data)
/* get the terms from the query box */
gchar* search_text =
gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
/* save this entry in the history */
lk_add_history(search_text);
/* launch the appropriate thing */
lk_launcher_launch(binding, search_text);
g_free(search_text);
g_free(search_text);
if (applet_mode) {
/* clear out the contents of the entry box */
gtk_entry_set_text(GTK_ENTRY(widget), "");
@@ -151,9 +205,11 @@ launch (GtkWidget* widget, gpointer data)
* instead of pressing some special key combination) */
gchar* search_text = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
lk_launcher_launch(NULL, search_text);
g_free(search_text);
if (applet_mode) {
/* save this entry in the history */
lk_add_history(search_text);
g_free(search_text);
/* clear out the contents of the entry box */
gtk_entry_set_text(GTK_ENTRY(widget), "");
} else {
@@ -195,6 +251,9 @@ lk_querybox_create (void)
gtk_box_pack_start(GTK_BOX(hbox), prefs, FALSE, FALSE, 0);
}
/* create the array of history commands */
lk_init_history();
return hbox;
}