From e76e311607a7893b3ffc6e1907e8c28d8983d2d1 Mon Sep 17 00:00:00 2001 From: Kalle Wallin Date: Sun, 6 Jun 2004 16:40:16 +0000 Subject: Added wreadln.c, wreadln.h a simple line editor git-svn-id: https://svn.musicpd.org/ncmpc/trunk@1351 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- src/Makefile.am | 5 +- src/main.c | 11 +- src/screen.c | 38 ++++-- src/screen.h | 1 + src/screen_utils.c | 44 ++++--- src/wreadln.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/wreadln.h | 25 ++++ 7 files changed, 428 insertions(+), 35 deletions(-) create mode 100644 src/wreadln.c create mode 100644 src/wreadln.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 59a7f4a70..ff4fb7aa9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,12 +11,13 @@ AM_CPPFLAGS = $(GLIB_CFLAGS) -DLOCALE_DIR=\""$(datadir)/locale"\" -DSYSCONFDIR=\ ncmpc_headers = libmpdclient.h mpc.h options.h conf.h command.h screen.h \ screen_utils.h screen_play.h screen_file.h screen_search.h \ - screen_help.h list_window.h colors.h support.h ncmpc.h + screen_help.h list_window.h colors.h support.h wreadln.h \ + ncmpc.h ncmpc_SOURCES = libmpdclient.c main.c mpc.c options.c conf.c command.c \ screen.c screen_utils.c screen_play.c screen_file.c \ screen_search.c screen_help.c screen_keydef.c \ - list_window.c colors.c support.c $(ncmpc_headers) + list_window.c colors.c support.c wreadln.c $(ncmpc_headers) diff --git a/src/main.c b/src/main.c index 1a3573e7a..176bcf8a0 100644 --- a/src/main.c +++ b/src/main.c @@ -69,13 +69,12 @@ main(int argc, const char *argv[]) gboolean connected; const char *charset = NULL; - /* initialize charset */ #ifdef HAVE_LOCALE_H - if( setlocale(LC_CTYPE,"") == NULL ) - { - g_printerr("setlocale() - failed!\n"); - exit(EXIT_FAILURE); - } + /* time and date formatting */ + setlocale(LC_TIME,""); + /* charset */ + setlocale(LC_CTYPE,""); + /* initialize charset conversions */ charset_init(g_get_charset(&charset)); D(printf("charset: %s\n", charset)); #endif diff --git a/src/screen.c b/src/screen.c index 4eac178b7..7522ad227 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1,5 +1,7 @@ /* - * (c) 2004 by Kalle Wallin (kaw@linux.se) + * $Id$ + * + * (c) 2004 by Kalle Wallin * * 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 @@ -32,6 +34,7 @@ #include "command.h" #include "options.h" #include "colors.h" +#include "wreadln.h" #include "screen.h" #include "screen_play.h" #include "screen_file.h" @@ -39,7 +42,7 @@ #include "screen_search.h" #include "screen_utils.h" -#undef ENABLE_STATUS_LINE_CLOCK +#define ENABLE_STATUS_LINE_CLOCK #define ENABLE_SCROLLING #define DEFAULT_CROSSFADE_TIME 10 @@ -294,15 +297,17 @@ paint_status_window(mpd_client_t *c) snprintf(screen->buf, screen->buf_size, " [%d kbps]", status->bitRate ); } } +#ifdef ENABLE_STATUS_LINE_CLOCK else { time_t timep; time(&timep); /* Note: setlocale(LC_TIME,"") should be used first */ - //strftime(screen->buf, screen->buf_size, "%X ", localtime(&timep)); - strftime(screen->buf, screen->buf_size, " %k:%M", localtime(&timep)); + //strftime(screen->buf, screen->buf_size, "%x - %X ",localtime(&timep)); + strftime(screen->buf, screen->buf_size, "%X ",localtime(&timep)); } +#endif /* display song */ if( (IS_PLAYING(status->state) || IS_PAUSED(status->state)) && song ) @@ -333,7 +338,20 @@ paint_status_window(mpd_client_t *c) wnoutrefresh(w); } - +GList * +screen_free_string_list(GList *list) +{ + GList *l = g_list_first(list); + + while(l) + { + g_free(l->data); + l->data = NULL; + l=l->next; + } + g_list_free(list); + return NULL; +} int screen_exit(void) @@ -356,9 +374,10 @@ screen_exit(void) list=list->next; } g_list_free(screen->screen_list); - + screen_free_string_list(screen->find_history); g_free(screen->buf); g_free(screen->findbuf); + g_free(screen); screen = NULL; } @@ -472,9 +491,9 @@ screen_init(void) noecho(); /* set cursor invisible */ curs_set(0); - /* return from getch() without blocking */ - // nodelay(stdscr, TRUE); + /* enable extra keys */ keypad(stdscr, TRUE); + /* return from getch() without blocking */ timeout(SCREEN_TIMEOUT); if( COLS * * 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 @@ -31,6 +33,7 @@ #include "options.h" #include "list_window.h" #include "colors.h" +#include "wreadln.h" #include "screen.h" #define FIND_PROMPT _("Find: ") @@ -63,31 +66,28 @@ screen_getch(WINDOW *w, char *prompt) return key; } - char * -screen_getstr(WINDOW *w, char *prompt) +screen_readln(WINDOW *w, + char *prompt, + char *value, + GList **history, + GCompletion *gcmp) { - char buf[256], *line = NULL; - int prompt_len = strlen(prompt); + char *line = NULL; - colors_use(w, COLOR_STATUS_ALERT); - wclear(w); - wmove(w, 0, 0); - waddstr(w, prompt); - wmove(w, 0, prompt_len); - - echo(); + wmove(w, 0,0); curs_set(1); - - if( wgetnstr(w, buf, 256) == OK ) - line = g_strdup(buf); - - noecho(); + line = wreadln(w, prompt, value, COLS, history, gcmp); curs_set(0); - return line; } +char * +screen_getstr(WINDOW *w, char *prompt) +{ + return screen_readln(w, prompt, NULL, NULL, NULL); +} + /* query user for a string and find it in a list window */ int @@ -121,7 +121,13 @@ screen_find(screen_t *screen, case CMD_LIST_FIND_NEXT: case CMD_LIST_RFIND_NEXT: if( !screen->findbuf ) - screen->findbuf=screen_getstr(screen->status_window.w, prompt); + screen->findbuf=screen_readln(screen->status_window.w, + prompt, + (char *) -1, //NULL, + &screen->find_history, + NULL); + if( !screen->findbuf || !screen->findbuf[0] ) + return 1; if( reversed ) retval = list_window_rfind(lw, callback_fn, diff --git a/src/wreadln.c b/src/wreadln.c new file mode 100644 index 000000000..6ac94b7dc --- /dev/null +++ b/src/wreadln.c @@ -0,0 +1,339 @@ +/* + * $Id$ + * + * (c) 2004 by Kalle Wallin + * + * 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 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 +#include +#include +#include + +#include "wreadln.h" + +#define KEY_CTRL_A 1 +#define KEY_CTRL_D 4 +#define KEY_CTRL_E 5 +#define KEY_CTRL_G 7 +#define KEY_CTRL_K 11 +#define KEY_BCKSPC 8 +#define TAB 9 + +#define WRLN_MAX_LINE_SIZE 1024 +#define WRLN_MAX_HISTORY_LENGTH 32 + +unsigned int wrln_max_line_size = WRLN_MAX_LINE_SIZE; +unsigned int wrln_max_history_length = WRLN_MAX_HISTORY_LENGTH; +GVoidFunc wrln_resize_callback = NULL; + + +char * +wreadln(WINDOW *w, + char *prompt, + char *initial_value, + int x1, + GList **history, + GCompletion *gcmp) +{ + GList *hlist = NULL, *hcurrent = NULL; + char *line; + int x0, y, width; + int cursor = 0, start = 0; + int key = 0, i; + + /* move the cursor one step to the right */ + void cursor_move_right(void) { + if( cursor < strlen(line) && cursor= x1 && start 0 ) + { + if( cursor==start && start > 0 ) + start--; + cursor--; + } + } + /* move the cursor to the end of the line */ + void cursor_move_to_eol(void) { + cursor = strlen(line); + if( cursor+x0 >= x1 ) + start = cursor-width+1; + } + /* draw line buffer and update cursor position */ + void drawline() { + wmove(w, y, x0); + /* clear input area */ + whline(w, ' ', width); + /* print visible part of the line buffer */ + waddnstr(w, line+start, width); + /* move the cursor to the correct position */ + wmove(w, y, x0 + cursor-start); + /* tell ncurses to redraw the screen */ + doupdate(); + } + + + /* allocate a line buffer */ + line = g_malloc0(wrln_max_line_size); + /* turn off echo */ + noecho(); + /* make shure the cursor is visible */ + curs_set(1); + /* print prompt string */ + if( prompt ) + waddstr(w, prompt); + /* retrive y and x0 position */ + getyx(w, y, x0); + /* check the x1 value */ + if( x1<=x0 || x1>COLS ) + x1 = COLS; + width = x1-x0; + /* clear input area */ + mvwhline(w, y, x0, ' ', width); + + if( history ) + { + /* append the a new line to our history list */ + *history = g_list_append(*history, g_malloc0(wrln_max_line_size)); + /* hlist points to the current item in the history list */ + hlist = g_list_last(*history); + hcurrent = hlist; + } + + if( initial_value == (char *) -1 ) + { + /* get previous history entry */ + if( history && hlist->prev ) + { + if( hlist==hcurrent ) + { + /* save the current line */ + strncpy(hlist->data, line, wrln_max_line_size); + } + /* get previous line */ + hlist = hlist->prev; + strncpy(line, hlist->data, wrln_max_line_size); + } + cursor_move_to_eol(); + drawline(); + } + else if( initial_value ) + { + /* copy the initial value to the line buffer */ + strncpy(line, initial_value, wrln_max_line_size); + cursor_move_to_eol(); + drawline(); + } + + while( key!=13 && key!='\n' ) + { + key = wgetch(w); + + /* check if key is a function key */ + for(i=0; i<63; i++) + if( key==KEY_F(i) ) + { + key=KEY_F(1); + i=64; + } + + switch (key) + { + case ERR: + /* ingnore errors */ + break; + + case KEY_RESIZE: + /* a resize event -> call an external callback function */ + if( wrln_resize_callback ) + wrln_resize_callback(); + if( x1>COLS ) + { + x1=COLS; + width = x1-x0; + cursor_move_to_eol(); + } + /* make shure the cursor is visible */ + curs_set(1); + break; + + case TAB: + if( gcmp && strlen(line)) + { + char *prefix = NULL; + GList *list; + + list = g_completion_complete(gcmp, line, &prefix); + if( prefix ) + { + int len = strlen(prefix); + strncpy(line, prefix, len); + cursor_move_to_eol(); + g_free(prefix); + } + else + beep(); + } + break; + + case KEY_CTRL_G: + beep(); + g_free(line); + if( history ) + { + g_free(hcurrent->data); + hcurrent->data = NULL; + *history = g_list_delete_link(*history, hcurrent); + } + return NULL; + + case KEY_LEFT: + cursor_move_left(); + break; + case KEY_RIGHT: + cursor_move_right(); + break; + case KEY_HOME: + case KEY_CTRL_A: + cursor = 0; + start = 0; + break; + case KEY_END: + case KEY_CTRL_E: + cursor_move_to_eol(); + break; + case KEY_CTRL_K: + line[cursor] = 0; + break; + case 127: + case KEY_BCKSPC: /* handle backspace: copy all */ + case KEY_BACKSPACE: /* chars starting from curpos */ + if( cursor > 0 ) /* - 1 from buf[n+1] to buf */ + { + for (i = cursor - 1; line[i] != 0; i++) + line[i] = line[i + 1]; + cursor_move_left(); + } + break; + case KEY_DC: /* handle delete key. As above */ + case KEY_CTRL_D: + if( cursor <= strlen(line) - 1 ) + { + for (i = cursor; line[i] != 0; i++) + line[i] = line[i + 1]; + } + break; + case KEY_UP: + /* get previous history entry */ + if( history && hlist->prev ) + { + if( hlist==hcurrent ) + { + /* save the current line */ + strncpy(hlist->data, line, wrln_max_line_size); + } + /* get previous line */ + hlist = hlist->prev; + strncpy(line, hlist->data, wrln_max_line_size); + } + // if (cursor > strlen(line)) + cursor_move_to_eol(); + break; + case KEY_DOWN: + /* get next history entry */ + if( history && hlist->next ) + { + /* get next line */ + hlist = hlist->next; + strncpy(line, hlist->data, wrln_max_line_size); + } + cursor_move_to_eol(); + break; + + case '\n': + case 13: + case KEY_IC: + case KEY_PPAGE: + case KEY_NPAGE: + case KEY_F(1): + /* ignore char */ + break; + default: + if (key >= 32) + { + if (strlen (line + cursor)) /* if the cursor is */ + { /* not at the last pos */ + char *tmp = 0; + tmp = g_malloc0(strlen (line + cursor) + 1); + strcpy (tmp, line + cursor); + line[cursor] = key; + line[cursor + 1] = 0; + strcat (&line[cursor + 1], tmp); + g_free(tmp); + cursor_move_right(); + } + else + { + line[cursor + 1] = 0; + line[cursor] = key; + cursor_move_right(); + } + } + } + + drawline(); + } + + /* update history */ + if( history ) + { + if( strlen(line) ) + { + /* update the current history entry */ + size_t size = strlen(line)+1; + hcurrent->data = g_realloc(hcurrent->data, size); + strncpy(hcurrent->data, line, size); + } + else + { + /* the line was empty - remove the current history entry */ + g_free(hcurrent->data); + hcurrent->data = NULL; + *history = g_list_delete_link(*history, hcurrent); + } + + while( g_list_length(*history) > wrln_max_history_length ) + { + GList *first = g_list_first(*history); + + /* remove the oldest history entry */ + g_free(first->data); + first->data = NULL; + *history = g_list_delete_link(*history, first); + } + } + + return g_realloc(line, strlen(line)+1); +} + + diff --git a/src/wreadln.h b/src/wreadln.h new file mode 100644 index 000000000..270d73fb1 --- /dev/null +++ b/src/wreadln.h @@ -0,0 +1,25 @@ +#ifndef WREADLN_H +#define WREADLN_H + +/* max size allocated for a line */ +extern unsigned int wrln_max_line_size; + +/* max items stored in the history list */ +extern unsigned int wrln_max_history_length; + +/* a callback function for KEY_RESIZE */ +extern GVoidFunc wrln_resize_callback; + +/* Note, wreadln calls curs_set() and noecho(), to enable cursor and + * disable echo. wreadln will not restore these settings when exiting! */ +char *wreadln(WINDOW *w, /* the curses window to use */ + char *prompt, /* the prompt string or NULL */ + char *initial_value, /* initial value or NULL for a empty line + * (char *) -1 => get value from history */ + int x1, /* the maximum x position or 0 */ + GList **history, /* a pointer to a history list or NULL */ + GCompletion *gcmp /* a GCompletion structure or NULL */ + ); + + +#endif -- cgit v1.2.3