Code

Added wreadln.c, wreadln.h a simple line editor
authorKalle Wallin <kaw@linux.se>
Sun, 6 Jun 2004 16:40:16 +0000 (16:40 +0000)
committerKalle Wallin <kaw@linux.se>
Sun, 6 Jun 2004 16:40:16 +0000 (16:40 +0000)
git-svn-id: https://svn.musicpd.org/ncmpc/trunk@1351 09075e82-0dd4-0310-85a5-a0d7c8717e4f

ChangeLog
src/Makefile.am
src/main.c
src/screen.c
src/screen.h
src/screen_utils.c
src/wreadln.c [new file with mode: 0644]
src/wreadln.h [new file with mode: 0644]

index e37371848dd63d147c8afc3f457f3b4d75b09b19..fcd582aea4d97b9bf573d80d49a1873a131e146c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2004-06-06 Kalle Wallin <kaw@linux.se>
        * i18n: ncmpc is now bilingual (sv)
+       * Moved all locale initialization code to main.c
+       * main.c: added bind_textdomain_codeset()       
+       * Added wreadln.c, wreadln.h a simple line editor
+       * screen_utils.c: use wreadln() instead of curses wgetstr()
+       * Added a history for the find command!
+
 
 2004-06-05 Kalle Wallin <kaw@linux.se>
        * Added initial i18n support
index 59a7f4a70a7cad1bfa941aca69c17b4a9701cc50..ff4fb7aa9926970663e85bfcf88f176ba6b492f8 100644 (file)
@@ -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)
 
 
 
index 1a3573e7a4a3e55c79ca080d212482fe1d8b7d98..176bcf8a04a45a55f69f7b361aa557d5e8c1add7 100644 (file)
@@ -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
index 4eac178b7965592667c632c76d6321b18f1ebcb2..7522ad2271ade612d26de08e9836096b6a1abe67 100644 (file)
@@ -1,5 +1,7 @@
 /* 
- * (c) 2004 by Kalle Wallin (kaw@linux.se)
+ * $Id$
+ *
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
  *
  * 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<SCREEN_MIN_COLS || LINES<SCREEN_MIN_ROWS )
@@ -575,6 +594,9 @@ screen_init(void)
 
   mode_fn = get_screen_playlist();
 
+  /* initialize wreadln */
+  wrln_resize_callback = screen_resize;
+
   return 0;
 }
 
index 75852d36e738da2994e571002ccce437599b1afa..cb4abc83d243f1b69e1cc5ec6ba2f3599ec10512 100644 (file)
@@ -53,6 +53,7 @@ typedef struct
   size_t buf_size;
 
   char *findbuf;
+  GList *find_history;
 
   int painted;
 
index 080b118b13fee989ca00f230fc21f8809ab50c4e..b14b2a0ee156b0b8c36ab0ed54893d6ee60df215 100644 (file)
@@ -1,5 +1,7 @@
 /* 
- * (c) 2004 by Kalle Wallin (kaw@linux.se)
+ * $Id$
+ *
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
  *
  * 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 (file)
index 0000000..6ac94b7
--- /dev/null
@@ -0,0 +1,339 @@
+/* 
+ * $Id$
+ *
+ * (c) 2004 by Kalle Wallin <kaw@linux.se>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include <glib.h>
+
+#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<wrln_max_line_size-1 )
+      {
+       cursor++;
+       if( cursor+x0 >= x1 && start<cursor-width+1)
+         start++;
+      }
+  }
+  /* move the cursor one step to the left */
+  void cursor_move_left(void) {
+    if( cursor > 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 (file)
index 0000000..270d73f
--- /dev/null
@@ -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