diff -Naur ratpoison/configure.in ratpoison.line-editor-patch/configure.in --- ratpoison/configure.in Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/configure.in Mon Aug 12 16:22:00 2002 @@ -60,6 +60,16 @@ AC_MSG_ERROR([*** Can't find X11 headers and libs]) fi +dnl Just a hack .... +AC_CHECK_LIB(history, add_history, [ AC_CHECK_HEADER(readline/history.h, HISTORY="yes")]) + + +if test "x$HISTORY" = "xyes"; then + LIBS="$LIBS -lhistory" +else + AC_MSG_ERROR([*** Can't find History headers and libs]) +fi + LDFLAGS="$LDFLAGS $X_LDFLAGS $X_LIBS $X_EXTRA_LIBS" CFLAGS="$CFLAGS $X_CFLAGS" @@ -74,7 +84,7 @@ dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for library functions. -AC_CHECK_FUNCS(getopt getopt_long setsid setpgid setpgrp setenv unsetenv vsnprintf ) +AC_CHECK_FUNCS(getopt getopt_long setsid setpgid setpgrp setenv unsetenv usleep vsnprintf) AC_TYPE_SIGNAL diff -Naur ratpoison/src/Makefile.am ratpoison.line-editor-patch/src/Makefile.am --- ratpoison/src/Makefile.am Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/Makefile.am Mon Aug 12 16:22:00 2002 @@ -29,11 +29,15 @@ communications.h \ conf.h \ data.h \ + editor.c \ + editor.h \ events.c \ events.h \ getopt.c \ getopt.h \ getopt1.c \ + history.c \ + history.h \ input.c \ input.h \ list.c \ diff -Naur ratpoison/src/actions.c ratpoison.line-editor-patch/src/actions.c --- ratpoison/src/actions.c Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/actions.c Mon Aug 12 16:22:00 2002 @@ -83,6 +83,7 @@ {"startup_message", cmd_startup_message, arg_STRING}, {"link", cmd_link, arg_STRING}, {"alias", cmd_alias, arg_STRING}, + {"history", cmd_history, arg_STRING}, {"unalias", cmd_unalias, arg_STRING}, {"prevscreen", cmd_prevscreen, arg_VOID}, {"nextscreen", cmd_nextscreen, arg_VOID}, @@ -105,6 +106,7 @@ {"deffgcolor", cmd_deffgcolor, arg_STRING}, {"defbgcolor", cmd_defbgcolor, arg_STRING}, {"defbarpadding", cmd_defbarpadding, arg_STRING}, + {"defhistorysize", cmd_defhistorysize, arg_STRING}, /* Commands to help debug ratpoison. */ #ifdef DEBUG @@ -2438,6 +2440,46 @@ } char * +cmd_defhistorysize (int interactive, void *data) +{ + int tmp; + + if (data == NULL && !interactive) + return xsprintf ("%d", defaults.history_size); + + if (data == NULL + || sscanf (data, "%d", &tmp) < 1) + { + message (" defhistorysize: One argument required "); + } + else if (tmp < 0 || tmp > MAX_HISTORY_SIZE) + { + message (" defhistorysize: Bad argument "); + } + else + { + defaults.history_size = tmp; + history_resize (defaults.history_size); + } + + return NULL; +} + +char * +cmd_history (int interactive, void *data) +{ + if (interactive) + { + /* TODO: display the history in a window */ + return NULL; + } + else + { + return history_list_items (); + } +} + +char * cmd_unalias (int interactive, void *data) { char *name; diff -Naur ratpoison/src/actions.h ratpoison.line-editor-patch/src/actions.h --- ratpoison/src/actions.h Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/actions.h Mon Aug 12 16:22:00 2002 @@ -90,6 +90,7 @@ char * cmd_defwinname (int interactive, void *data); char * cmd_deffgcolor (int interactive, void *data); char * cmd_defbgcolor (int interactive, void *data); +char * cmd_defhistorysize (int interactive, void *data); char * cmd_setenv (int interactive, void *data); char * cmd_getenv (int interactive, void *data); char * cmd_chdir (int interactive, void *data); @@ -104,6 +105,7 @@ char * cmd_startup_message (int interactive, void *data); char * cmd_focuslast (int interactive, void *data); char * cmd_link (int interactive, void *data); +char * cmd_history (int interactive, void *data); char * cmd_defbarpadding (int interactive, void *data); char * cmd_license (int interactive, void *data); char * cmd_alias (int interactive, void *data); diff -Naur ratpoison/src/conf.h ratpoison.line-editor-patch/src/conf.h --- ratpoison/src/conf.h Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/conf.h Mon Aug 12 16:22:00 2002 @@ -41,7 +41,7 @@ #define INPUT_NEXT_HISTORY_MODIFIER ControlMask /* Number of history items to store. */ -#define INPUT_MAX_HISTORY 50 +/*#define INPUT_MAX_HISTORY 50*/ /* Treat windows with maxsize hints as if they were a transient window (don't hide the windows underneath, and center them) */ @@ -73,4 +73,13 @@ about bad window messages. */ #define IGNORE_BADWINDOW 1 +/* Maximum allowed history size */ +#define MAX_HISTORY_SIZE 100 + +/* The default filename in which to store the history */ +#define HISTORY_FILE ".ratpoison_history" + +/* Use a visual bell in the input window */ +#define VISUAL_BELL + #endif /* !_ _RATPOISON_CONF_H */ diff -Naur ratpoison/src/data.h ratpoison.line-editor-patch/src/data.h --- ratpoison/src/data.h Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/data.h Mon Aug 12 16:22:00 2002 @@ -27,6 +27,7 @@ #include #define FONT_HEIGHT(f) ((f)->max_bounds.ascent + (f)->max_bounds.descent) +#define MAX_FONT_WIDTH(f) ((f)->max_bounds.width) #define WIN_EVENTS (StructureNotifyMask | PropertyChangeMask | ColormapChangeMask | FocusChangeMask) @@ -160,6 +161,7 @@ int win_name; int startup_message; + int history_size; }; extern struct rp_defaults defaults; @@ -195,6 +197,7 @@ extern Atom rp_command; extern Atom rp_command_request; extern Atom rp_command_result; +extern Atom rp_selection; extern Atom wm_state; extern Atom wm_change_state; diff -Naur ratpoison/src/editor.c ratpoison.line-editor-patch/src/editor.c --- ratpoison/src/editor.c Thu Jan 1 10:00:00 1970 +++ ratpoison.line-editor-patch/src/editor.c Mon Aug 12 16:22:00 2002 @@ -0,0 +1,482 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ratpoison.h" + +static char *saved_command = NULL; + +static edit_binding edit_bindings[] = + { {"C-g", editor_abort}, + {"Escape", editor_abort}, + {"C-f", editor_forward_char}, + {"Right", editor_forward_char}, + {"C-b", editor_backward_char}, + {"Left", editor_backward_char}, + {"M-f", editor_forward_word}, + {"M-b", editor_backward_word}, + {"C-a", editor_beginning_of_line}, + {"Home", editor_beginning_of_line}, + {"C-e", editor_end_of_line}, + {"End", editor_end_of_line}, + {"C-d", editor_delete_char}, + {"Delete", editor_delete_char}, + {"BackSpace", editor_backward_delete_char}, + {"M-d", editor_kill_word}, + {"C-w", editor_backward_kill_word}, + {"C-k", editor_kill_line}, + {"C-u", editor_kill_whole_line}, + {"C-bracketright", editor_paste_selection}, + {"Insert", editor_paste_selection}, + {"C-p", editor_history_previous}, + {"Up", editor_history_previous}, + {"C-n", editor_history_next}, + {"Down", editor_history_next}, + {"Return", editor_enter}, + {"KP_Enter", editor_enter}, + { 0, 0} }; + +edit_status +execute_edit_action (input_line *line, KeySym ch, unsigned int modifier, char *keysym_buf, int nbytes) +{ + struct edit_binding *binding = NULL; + int found_binding = 0; + char *keysym_name; + edit_status status; + + keysym_name = keysym_to_string (ch, x11_mask_to_rp_mask (modifier)); + + PRINT_DEBUG ("keysym = %s\n", keysym_name); + + for (binding = edit_bindings; binding->key; binding++) + { + if (!strcmp (keysym_name, binding->key)) + { + found_binding = 1; + break; + } + } + + free (keysym_name); + + if (found_binding) + status = binding->func (line); + else if (modifier) + status = editor_no_action (line); + else + status = editor_insert (line, keysym_buf, nbytes); + + return status; +} + +edit_status +editor_forward_char (input_line *line) +{ + if (line->position < line->length) + { + line->position++; + return EDIT_MOVE; + } + else + return EDIT_NO_OP; + +} + +edit_status +editor_backward_char (input_line *line) +{ + if (line->position > 0) + { + line->position--; + return EDIT_MOVE; + } + else + return EDIT_NO_OP; +} + +edit_status +editor_forward_word (input_line *line) +{ + if (line->position < line->length) + { + for (; line->position < line->length && !isalnum (line->buffer[line->position]); line->position++); + for (; line->position < line->length && isalnum (line->buffer[line->position]); line->position++); + } + + return EDIT_MOVE; +} + +edit_status +editor_backward_word (input_line *line) +{ + if (line->position > 0) + { + for (; line->position > 0 && !isalnum (line->buffer[line->position - 1]); line->position--); + for (; line->position > 0 && isalnum (line->buffer[line->position - 1]); line->position--); + } + + return EDIT_MOVE; +} + +edit_status +editor_beginning_of_line (input_line *line) +{ + if (line->position > 0) + line->position = 0; + + return EDIT_MOVE; +} + +edit_status +editor_end_of_line (input_line *line) +{ + if (line->position < line->length) + line->position = line->length; + + return EDIT_MOVE; +} + +edit_status +editor_delete_char (input_line *line) +{ + int i; + + if (line->position < line->length) + { + for (i = line->position; i < line->length; i++) + line->buffer[i] = line->buffer[i + 1]; + + line->length--; + return EDIT_DELETE; + } + else + return EDIT_NO_OP; +} + +edit_status +editor_backward_delete_char (input_line *line) +{ + int i; + + if (line->position > 0) + { + for (i = line->position - 1; i < line->length; i++) + line->buffer[i] = line->buffer[i + 1]; + + line->position--; + line->length--; + return EDIT_DELETE; + } + else + return EDIT_NO_OP; +} + +edit_status +editor_kill_word (input_line *line) +{ + int i, diff; + + if (line->position < line->length) + { + for (i = line->position; i < line->length && !isalnum (line->buffer[i]); i++); + for (; i < line->length && isalnum (line->buffer[i]); i++); + + diff = i - line->position; + + for (i = line->position; i <= line->length - diff; i++) + line->buffer[i] = line->buffer[i + diff]; + + line->length -= diff; + } + + return EDIT_DELETE; +} + +edit_status +editor_backward_kill_word (input_line *line) +{ + int i, diff; + + if (line->position > 0) + { + for (i = line->position; i > 0 && !isalnum (line->buffer[i - 1]); i--); + for (; i > 0 && isalnum (line->buffer[i - 1]); i--); + + diff = line->position - i; + + line->position = i; + + for (; i <= line->length - diff; i++) + line->buffer[i] = line->buffer[i + diff]; + + line->length -= diff; + } + + return EDIT_DELETE; +} + +edit_status +editor_kill_line (input_line *line) +{ + if (line->position < line->length) + { + line->length = line->position; + line->buffer[line->length] = 0; + } + + return EDIT_DELETE; +} + +edit_status +editor_kill_whole_line (input_line *line) +{ + if (line->length > 0) + { + line->length = line->position = 0; + line->buffer[line->length] = 0; + } + + return EDIT_DELETE; +} + +edit_status +editor_history_previous (input_line *line) +{ + char *entry = history_previous (); + + if (entry) + { + if (!saved_command) + { + line->buffer[line->length] = '\0'; + saved_command = xstrdup (line->buffer); + PRINT_DEBUG ("saved current command line: \'%s\'\n", saved_command); + } + + free (line->buffer); + line->buffer = xstrdup (entry); + line->length = strlen (line->buffer); + line->size = line->length + 1; + line->position = line->length; + PRINT_DEBUG ("entry: \'%s\'\n", line->buffer); + } + else + { + PRINT_DEBUG ("- do nothing -"); + return EDIT_NO_OP; + } + + return EDIT_INSERT; +} + +edit_status +editor_history_next (input_line *line) +{ + char *entry = history_next (); + + if (entry) + { + free (line->buffer); + line->buffer = xstrdup (entry); + PRINT_DEBUG ("entry: \'%s\'\n", line->buffer); + } + else if (saved_command) + { + free (line->buffer); + line->buffer = saved_command; + saved_command = NULL; + PRINT_DEBUG ("restored command line: \'%s\'\n", line->buffer); + } + else + { + PRINT_DEBUG ("- do nothing -"); + return EDIT_NO_OP; + } + + line->length = strlen (line->buffer); + line->size = line->length + 1; + line->position = line->length; + + return EDIT_INSERT; +} + +edit_status +editor_abort (input_line *line) +{ + free (line->buffer); + return EDIT_ABORT; +} + +edit_status +editor_no_action (input_line *line) +{ + return EDIT_NO_OP; +} + +edit_status +editor_insert (input_line *line, char *keysym_buf, int nbytes) +{ + int i; + + PRINT_DEBUG ("keysym_buf: '%s'\n", keysym_buf); + + if (line->length + nbytes > line->size - 1) + { + line->size += nbytes + 100; + line->buffer = xrealloc (line->buffer, line->size); + } + + for (i = line->length + nbytes; i > line->position; i--) + line->buffer[i] = line->buffer[i - nbytes]; + + strncpy (&line->buffer[line->position], keysym_buf, nbytes); + + line->length += nbytes; + line->position += nbytes; + + PRINT_DEBUG ("line->buffer: '%s'\n", line->buffer); + + return EDIT_INSERT; +} + +edit_status +editor_enter (input_line *line) +{ + int result; + char *expansion; + + line->buffer[line->length] = '\0'; + result = history_expand_line (line->buffer, &expansion); + + PRINT_DEBUG ("History Expansion - result: %d\n", result); + PRINT_DEBUG ("History Expansion - expansion: \'%s\'\n", expansion); + + if (result == -1 || result == 2) + { + marked_message_printf (0, 0, " %s ", expansion); + free (expansion); + line->buffer = NULL; + } + else /* result == 0 || result == 1 */ + { + history_add (expansion); + line->buffer = expansion; + } + + return EDIT_DONE; +} + +static edit_status +paste_cut_buffer (input_line *line) +{ + int nbytes; + char *data; + edit_status status; + + PRINT_DEBUG ("trying the cut buffer\n"); + + data = XFetchBytes (dpy, &nbytes); + + if (data) + { + status = editor_insert (line, data, nbytes); + XFree (data); + } + else + { + status = EDIT_NO_OP; + } + + return status; +} + +static edit_status +paste_primary_selection (input_line *line) +{ + Atom actual_type; + screen_info *s = current_screen (); + int actual_format; + unsigned long nitems; + unsigned long offset; + unsigned long bytes_after; + unsigned char *data; + + if (XGetWindowProperty (dpy, s->input_window, rp_selection, 0, 0, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &data) == Success) + { + if (data) + XFree (data); + + PRINT_DEBUG ("actual_type = %ld, actual_format = %d, bytes_after = %ld\n", actual_type, actual_format, bytes_after); + + if (actual_type != XA_STRING || actual_format != 8) + { + PRINT_DEBUG ("selection data is invalid\n"); + if (data) + XFree (data); + return EDIT_NO_OP; + } + + offset = 0; + + while (bytes_after > 0) + { + if (XGetWindowProperty (dpy, s->input_window, rp_selection, offset / 4, bytes_after / 4 + 1, False, XA_STRING, &actual_type, &actual_format, &nitems, &bytes_after, &data) != Success) + break; + + PRINT_DEBUG ("bytes_after = %ld, nitems = %ld, data = '%s'\n", bytes_after, nitems, data); + + nitems *= actual_format / 8; + offset += nitems; + + editor_insert (line, data, nitems); + + PRINT_DEBUG ("bytes_after = %ld, nitems = %ld, data = '%s'\n", bytes_after, nitems, data); + + XFree (data); + } + } + + /* notify the owner that the data has been transferred */ + XDeleteProperty(dpy, s->input_window, rp_selection); + + return EDIT_INSERT; +} + +edit_status +editor_paste_selection (input_line *line) +{ + Atom property; + XEvent ev; + screen_info *s = current_screen (); + int loops = 1000; + + /* be a good icccm citizen */ + XDeleteProperty (dpy, s->input_window, rp_selection); + /* TODO: we shouldn't use CurrentTime here, use the time of the XKeyEvent, should we fake it? */ + XConvertSelection (dpy, XA_PRIMARY, XA_STRING, rp_selection, s->input_window, CurrentTime); + + while (!XCheckTypedWindowEvent (dpy, s->input_window, SelectionNotify, &ev)) + { + if (loops == 0) + { + return EDIT_NO_OP; PRINT_ERROR ("selection request timed out\n"); + } + usleep (10000); + loops--; + } + + PRINT_DEBUG ("SelectionNotify event\n"); + + property = ev.xselection.property; + + if (property != None) + return paste_primary_selection (line); + else + return paste_cut_buffer (line); +} diff -Naur ratpoison/src/editor.h ratpoison.line-editor-patch/src/editor.h --- ratpoison/src/editor.h Thu Jan 1 10:00:00 1970 +++ ratpoison.line-editor-patch/src/editor.h Mon Aug 12 16:22:00 2002 @@ -0,0 +1,51 @@ +#ifndef _RATPOISON_EDITOR_H +#define _RATPOISON_EDITOR_H 1 + +typedef enum edit_status edit_status; + +enum +edit_status +{ + EDIT_INSERT, + EDIT_DELETE, + EDIT_MOVE, + EDIT_ABORT, + EDIT_DONE, + EDIT_NO_OP +}; + +typedef struct edit_binding edit_binding; + +struct +edit_binding +{ + char *key; + edit_status (*func)(input_line *); +}; + +/* bind functions */ +edit_status editor_forward_char (input_line *line); +edit_status editor_backward_char (input_line *line); +edit_status editor_forward_word (input_line *line); +edit_status editor_backward_word (input_line *line); +edit_status editor_beginning_of_line (input_line *line); +edit_status editor_end_of_line (input_line *line); +edit_status editor_delete_char (input_line *line); +edit_status editor_backward_delete_char (input_line *line); +edit_status editor_kill_word (input_line *line); +edit_status editor_backward_kill_word (input_line *line); +edit_status editor_kill_line (input_line *line); +edit_status editor_kill_whole_line (input_line *line); +edit_status editor_paste_selection (input_line *line); +edit_status editor_abort (input_line *line); +edit_status editor_no_action (input_line *line); +edit_status editor_enter (input_line *line); +edit_status editor_history_previous (input_line *line); +edit_status editor_history_next (input_line *line); + +/* default edit action */ +edit_status editor_insert (input_line *line, char *keysym_buf, int nbytes); + +edit_status execute_edit_action (input_line *line, KeySym ch, unsigned int modifier, char *keysym_buf, int nbytes); + +#endif /* ! _RATPOISON_EDITOR_H */ diff -Naur ratpoison/src/history.c ratpoison.line-editor-patch/src/history.c --- ratpoison/src/history.c Thu Jan 1 10:00:00 1970 +++ ratpoison.line-editor-patch/src/history.c Mon Aug 12 16:22:00 2002 @@ -0,0 +1,127 @@ +#include +#include +#include + +#include "ratpoison.h" +#include "readline/history.h" + +static char * +get_history_filename () +{ + char *homedir = getenv ("HOME"); + char *filename; + + if (homedir) + { + filename = xmalloc (strlen (homedir) + strlen ("/" HISTORY_FILE) + 1); + sprintf (filename, "%s/" HISTORY_FILE, homedir); + } + else + { + filename = xstrdup (HISTORY_FILE); + } + + return filename; +} + +void +history_load () +{ + char *filename = get_history_filename (); + + if (filename && read_history (filename) != 0) + PRINT_DEBUG ("ratpoison: could not read %s - %s\n", filename, strerror (errno)); + + using_history(); + + free (filename); +} + +void +history_save () +{ + char *filename = get_history_filename (); + + using_history (); + + if (filename && write_history (filename) != 0) + PRINT_ERROR ("ratpoison: could not write %s - %s\n", filename, strerror (errno)); + + free (filename); +} + +void +history_resize (int size) +{ + stifle_history (size); +} + +void +history_reset () +{ + using_history(); +} + +void +history_add (char *item) +{ + HIST_ENTRY *h = history_get (history_length); + + if (item == NULL || *item == '\0' || isspace (*item) || (h != NULL && !strcmp (h->line, item))) + return; + + PRINT_DEBUG ("Adding item: %s\n", item); + add_history (item); + using_history(); +} + +char * +history_previous () +{ + HIST_ENTRY *h = NULL; + + h = previous_history(); + + return h ? h->line : NULL; +} + +char * +history_next () +{ + HIST_ENTRY *h = NULL; + + h = next_history(); + + return h ? h->line : NULL; +} + +char * +history_list_items () +{ + HIST_ENTRY **hlist; + struct sbuf *list; + char *tmp; + int i; + + list = sbuf_new (0); + hlist = history_list (); + + if (!hlist) return NULL; + + for (i = 0; hlist[i] != NULL; i++) + { + sbuf_concat (list, hlist[i]->line); + if (i < history_length - 1) + sbuf_concat (list, "\n"); + } + + tmp = sbuf_get (list); + free (list); + + return tmp; +} + +int history_expand_line (char *string, char **output) +{ + return history_expand (string, output); +} diff -Naur ratpoison/src/history.h ratpoison.line-editor-patch/src/history.h --- ratpoison/src/history.h Thu Jan 1 10:00:00 1970 +++ ratpoison.line-editor-patch/src/history.h Mon Aug 12 16:22:00 2002 @@ -0,0 +1,14 @@ +#ifndef _RATPOISON_HISTORY_H +#define _RATPOISON_HISTORY_H 1 + +void history_load (); +void history_save (); +void history_resize (int size); +void history_reset (); +void history_add (char *item); +char *history_next (); +char *history_previous (); +char *history_list_items (); +int history_expand_line (char *string, char **output); + +#endif /* ! _RATPOISON_HISTORY_H */ diff -Naur ratpoison/src/input.c ratpoison.line-editor-patch/src/input.c --- ratpoison/src/input.c Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/input.c Mon Aug 12 16:22:00 2002 @@ -22,16 +22,13 @@ #include #include #include +#include #include #include #include #include "ratpoison.h" -/* Variables to keep track of input history. */ -static char *input_history[INPUT_MAX_HISTORY]; -static int input_num_history_entries = 0; - /* Convert an X11 modifier mask to the rp modifier mask equivalent, as best it can (the X server may not have a hyper key defined, for instance). */ @@ -274,21 +271,23 @@ } static void -update_input_window (screen_info *s, char *prompt, char *input, int input_len) +update_input_window (screen_info *s, input_line *line) { - int prompt_width = XTextWidth (defaults.font, prompt, strlen (prompt)); - int input_width = XTextWidth (defaults.font, input, input_len); - int width; + int prompt_width = XTextWidth (defaults.font, line->prompt, strlen (line->prompt)); + int input_width = XTextWidth (defaults.font, line->buffer, line->length); + int total_width; + GC lgc; + XGCValues gv; - width = defaults.bar_x_padding * 2 + prompt_width + input_width; + total_width = defaults.bar_x_padding * 2 + prompt_width + input_width + MAX_FONT_WIDTH (defaults.font); - if (width < defaults.input_window_size + prompt_width) + if (total_width < defaults.input_window_size + prompt_width) { - width = defaults.input_window_size + prompt_width; + total_width = defaults.input_window_size + prompt_width; } XMoveResizeWindow (dpy, s->input_window, - bar_x (s, width), bar_y (s), width, + bar_x (s, total_width), bar_y (s), total_width, (FONT_HEIGHT (defaults.font) + defaults.bar_y_padding * 2)); XClearWindow (dpy, s->input_window); @@ -296,20 +295,67 @@ XDrawString (dpy, s->input_window, s->normal_gc, defaults.bar_x_padding, - defaults.bar_y_padding + defaults.font->max_bounds.ascent, prompt, - strlen (prompt)); + defaults.bar_y_padding + defaults.font->max_bounds.ascent, + line->prompt, + strlen (line->prompt)); XDrawString (dpy, s->input_window, s->normal_gc, defaults.bar_x_padding + prompt_width, - defaults.bar_y_padding + defaults.font->max_bounds.ascent, input, - input_len); + defaults.bar_y_padding + defaults.font->max_bounds.ascent, + line->buffer, + line->length); + + gv.function = GXxor; + gv.foreground = s->fg_color ^ s->bg_color; + lgc = XCreateGC (dpy, s->input_window, GCFunction | GCForeground, &gv); + + /* Draw a cheap-o cursor - MkII */ + XFillRectangle (dpy, s->input_window, lgc, + defaults.bar_x_padding + prompt_width + XTextWidth (defaults.font, line->buffer, line->position), + defaults.bar_y_padding, + XTextWidth (defaults.font, &line->buffer[line->position], 1), + FONT_HEIGHT (defaults.font)); + + XFlush (dpy); + XFreeGC (dpy, lgc); +} + +void +ring_bell () +{ +#ifdef VISUAL_BELL + GC lgc; + XGCValues gv; + XWindowAttributes attr; + screen_info *s = current_screen (); + + XGetWindowAttributes (dpy, s->input_window, &attr); + + gv.function = GXxor; + gv.foreground = s->fg_color ^ s->bg_color; + lgc = XCreateGC (dpy, s->input_window, GCFunction | GCForeground, &gv); + + XFillRectangle (dpy, s->input_window, lgc, 0, 0, attr.width, attr.height); + XFlush (dpy); + + #ifdef HAVE_USLEEP + usleep (15000); + #else + { + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 15000; + select (0, NULL, NULL, NULL, &tv); + } + #endif - /* Draw a cheap-o cursor. */ - XDrawLine (dpy, s->input_window, s->normal_gc, - defaults.bar_x_padding + prompt_width + input_width + 2, - defaults.bar_y_padding + 1, - defaults.bar_x_padding + prompt_width + input_width + 2, - defaults.bar_y_padding + FONT_HEIGHT (defaults.font) - 1); + XFillRectangle (dpy, s->input_window, lgc, 0, 0, attr.width, attr.height); + XFlush (dpy); + XFreeGC (dpy, lgc); +#else + XBell (dpy, 0); +#endif } char * @@ -326,21 +372,24 @@ int keysym_bufsize = sizeof (keysym_buf); int nbytes; screen_info *s = current_screen (); - int cur_len = 0; /* Current length of the string. */ - int allocated_len=100; /* The amount of memory we allocated for str */ KeySym ch; unsigned int modifier; int revert; Window fwin; - char *str; - int history_index = input_num_history_entries; - - /* Allocate some memory to start with. */ - str = (char *) xmalloc ( allocated_len ); + input_line *line; + char *final_input; + edit_status status; + + line = xmalloc (sizeof (input_line)); + line->prompt = prompt; + + /* Allocate some memory to start with */ + line->size = strlen (preinput) + 100; + line->buffer = (char *) xmalloc (line->size); /* load in the preinput */ - strcpy (str, preinput); - cur_len = strlen (preinput); + strcpy (line->buffer, preinput); + line->position = line->length = strlen (preinput); /* We don't want to draw overtop of the program bar. */ hide_bar (s); @@ -350,108 +399,40 @@ XClearWindow (dpy, s->input_window); XSync (dpy, False); - update_input_window (s, prompt, str, cur_len); + update_input_window (s, line); XGetInputFocus (dpy, &fwin, &revert); XSetInputFocus (dpy, s->input_window, RevertToPointerRoot, CurrentTime); /* XSync (dpy, False); */ - - nbytes = read_key (&ch, &modifier, keysym_buf, keysym_bufsize); - while (ch != XK_Return) + for (;;) { - PRINT_DEBUG ("key %ld\n", ch); - if (ch == XK_BackSpace) - { - if (cur_len > 0) cur_len--; - update_input_window(s, prompt, str, cur_len); - } - else if (ch == INPUT_PREV_HISTORY_KEY - && modifier == INPUT_PREV_HISTORY_MODIFIER) - { - /* Cycle through the history. */ - if (input_num_history_entries > 0) - { - history_index--; - if (history_index < 0) - { - history_index = input_num_history_entries - 1; - } - - free (str); - str = xstrdup (input_history[history_index]); - allocated_len = strlen (str) + 1; - cur_len = allocated_len - 1; - - update_input_window (s, prompt, str, cur_len); - } - } - else if (ch == INPUT_NEXT_HISTORY_KEY - && modifier == INPUT_NEXT_HISTORY_MODIFIER) - { - /* Cycle through the history. */ - if (input_num_history_entries > 0) - { - history_index++; - if (history_index >= input_num_history_entries) - { - history_index = 0; - } - - free (str); - str = xstrdup (input_history[history_index]); - allocated_len = strlen (str) + 1; - cur_len = allocated_len - 1; - - update_input_window (s, prompt, str, cur_len); - } - } - else if (ch == INPUT_ABORT_KEY && modifier == INPUT_ABORT_MODIFIER) - { - /* User aborted. */ - free (str); - XSetInputFocus (dpy, fwin, RevertToPointerRoot, CurrentTime); - XUnmapWindow (dpy, s->input_window); - return NULL; - } - else - { - if (cur_len + nbytes > allocated_len - 1) - { - allocated_len += nbytes + 100; - str = xrealloc ( str, allocated_len ); - } - - strncpy (&str[cur_len], keysym_buf, nbytes); -/* str[cur_len] = ch; */ - cur_len+=nbytes; - - update_input_window(s, prompt, str, cur_len); - } - nbytes = read_key (&ch, &modifier, keysym_buf, keysym_bufsize); - } + PRINT_DEBUG ( "ch = %ld, modifier = %d, keysym_buf = %s, keysym_bufsize = %d\n", ch, modifier, keysym_buf, keysym_bufsize ); + status = execute_edit_action (line, ch, modifier, keysym_buf, nbytes); - str[cur_len] = 0; - - /* Push the history entries down. */ - if (input_num_history_entries >= INPUT_MAX_HISTORY) - { - int i; - free (input_history[0]); - for (i=0; ibuffer; + break; + } } - /* Store the string in the history. */ - input_history[input_num_history_entries] = xstrdup (str); - input_num_history_entries++; - - XSetInputFocus (dpy, fwin, RevertToPointerRoot, CurrentTime); - XUnmapWindow (dpy, s->input_window); - return str; -} + XSetInputFocus (dpy, fwin, RevertToPointerRoot, CurrentTime); + XUnmapWindow (dpy, s->input_window); + + return final_input; +} diff -Naur ratpoison/src/input.h ratpoison.line-editor-patch/src/input.h --- ratpoison/src/input.h Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/input.h Mon Aug 12 16:22:00 2002 @@ -22,6 +22,20 @@ #ifndef _RATPOISON_INPUT_H #define _RATPOISON_INPUT_H 1 +typedef struct input_line input_line; + +struct +input_line +{ + char *buffer; + char *prompt; + char *saved; + int position; + int length; + int size; + Atom selection; +}; + char *keysym_to_string (KeySym keysym, unsigned int modifier); int cook_keycode (XKeyEvent *ev, KeySym *keysym, unsigned int *mod, char *keysym_name, int len, int ignore_bad_mods); char *get_input (char *prompt); @@ -31,5 +45,6 @@ unsigned int rp_mask_to_x11_mask (unsigned int mask); void update_modifier_map (); void grab_key (int keycode, unsigned int modifiers, Window grab_window); +void ring_bell (); #endif /* ! _RATPOISON_INPUT_H */ diff -Naur ratpoison/src/main.c ratpoison.line-editor-patch/src/main.c --- ratpoison/src/main.c Mon Aug 12 16:21:52 2002 +++ ratpoison.line-editor-patch/src/main.c Mon Aug 12 16:22:00 2002 @@ -55,6 +55,7 @@ Atom rp_command; Atom rp_command_request; Atom rp_command_result; +Atom rp_selection; int rp_current_screen; screen_info *screens; @@ -449,6 +450,7 @@ defaults.win_name = 0; defaults.startup_message = 1; + defaults.history_size = 20; } int @@ -506,6 +508,7 @@ rp_command = XInternAtom (dpy, "RP_COMMAND", False); rp_command_request = XInternAtom (dpy, "RP_COMMAND_REQUEST", False); rp_command_result = XInternAtom (dpy, "RP_COMMAND_RESULT", False); + rp_selection = XInternAtom (dpy, "RP_SELECTION", False); if (cmd_count > 0) { @@ -555,6 +558,7 @@ init_frame_lists (); update_modifier_map (); initialize_default_keybindings (); + history_load (); /* Scan for windows */ rp_current_screen = 0; @@ -669,6 +673,9 @@ { int i; + history_save (); + + for (i=0; i