X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fwreadln.c;h=0bfc414086a7ac541b990d776492a74f146576c0;hb=62388ceda61d89a9a58c5ba6181150912f67b93a;hp=5962af703e631ca7eae6bd59b7fbb407ee15cf1b;hpb=1c9015ebba6e6f25e47c614f24696e247e5939ce;p=ncmpc.git diff --git a/src/wreadln.c b/src/wreadln.c index 5962af7..0bfc414 100644 --- a/src/wreadln.c +++ b/src/wreadln.c @@ -18,6 +18,7 @@ #include "wreadln.h" #include "charset.h" +#include "screen_utils.h" #include "config.h" #include @@ -39,82 +40,101 @@ #define KEY_BCKSPC 8 #define TAB 9 -#define WRLN_MAX_LINE_SIZE 1024 -#define WRLN_MAX_HISTORY_LENGTH 32 - -guint wrln_max_line_size = WRLN_MAX_LINE_SIZE; -guint wrln_max_history_length = WRLN_MAX_HISTORY_LENGTH; +struct wreadln { + /** the ncurses window where this field is displayed */ + WINDOW *const w; + + /** the origin coordinates in the window */ + gint x, y; + + /** the screen width of the input field */ + gint width; + + /** is the input masked, i.e. characters displayed as '*'? */ + const gboolean masked; + + /** the byte position of the cursor */ + gint cursor; + + /** the byte position displayed at the origin (for horizontal + scrolling) */ + gint start; + + /** the current value */ + gchar line[1024]; +}; + +/** max items stored in the history list */ +static const guint wrln_max_history_length = 32; + void *wrln_completion_callback_data = NULL; wrln_gcmp_pre_cb_t wrln_pre_completion_callback = NULL; wrln_gcmp_post_cb_t wrln_post_completion_callback = NULL; -extern void sigstop(void); -extern void screen_bell(void); - /* move the cursor one step to the right */ -static inline void cursor_move_right(gint *cursor, - gint *start, - gint width, - gint x0, - gint x1, - gchar *line) +static inline void cursor_move_right(struct wreadln *wr) { - if (*cursor < (int)strlen(line) && - *cursor < (int)wrln_max_line_size - 1) { - (*cursor)++; - if (*cursor + x0 >= x1 && *start < *cursor - width + 1) - (*start)++; + if (wr->cursor < (int)strlen(wr->line)) { + ++wr->cursor; + if (wr->cursor >= wr->width && + wr->start < wr->cursor - wr->width + 1) + ++wr->start; } } /* move the cursor one step to the left */ -static inline void cursor_move_left(gint *cursor, - gint *start) +static inline void cursor_move_left(struct wreadln *wr) { - if (*cursor > 0) { - if (*cursor == *start && *start > 0) - (*start)--; - (*cursor)--; + if (wr->cursor > 0) { + if (wr->cursor == wr->start && wr->start > 0) + --wr->start; + --wr->cursor; } } /* move the cursor to the end of the line */ -static inline void cursor_move_to_eol(gint *cursor, - gint *start, - gint width, - gint x0, - gint x1, - gchar *line) +static inline void cursor_move_to_eol(struct wreadln *wr) { - *cursor = strlen(line); - if (*cursor + x0 >= x1) - *start = *cursor - width + 1; + wr->cursor = strlen(wr->line); + if (wr->cursor >= wr->width) + wr->start = wr->cursor - wr->width + 1; } /* draw line buffer and update cursor position */ -static inline void drawline(gint cursor, - gint start, - gint width, - gint x0, - gint y, - gboolean masked, - gchar *line, - WINDOW *w) +static inline void drawline(const struct wreadln *wr) { - wmove(w, y, x0); + wmove(wr->w, wr->y, wr->x); /* clear input area */ - whline(w, ' ', width); + whline(wr->w, ' ', wr->width); /* print visible part of the line buffer */ - if(masked == TRUE) - whline(w, '*', utf8_width(line) - start); + if (wr->masked) + whline(wr->w, '*', utf8_width(wr->line) - wr->start); else - waddnstr(w, line+start, width); + waddnstr(wr->w, wr->line + wr->start, wr->width); /* move the cursor to the correct position */ - wmove(w, y, x0 + cursor-start); + wmove(wr->w, wr->y, wr->x + wr->cursor - wr->start); /* tell ncurses to redraw the screen */ doupdate(); } +static void +wreadln_insert_byte(struct wreadln *wr, gint key) +{ + if (strlen(wr->line + wr->cursor)) { /* if the cursor is */ + /* not at the last pos */ + gsize rest = strlen(wr->line + wr->cursor) + 1; + + memmove(wr->line + wr->cursor + 1, + wr->line + wr->cursor, rest); + wr->line[wr->cursor] = key; + } else { + wr->line[wr->cursor + 1] = 0; + wr->line[wr->cursor] = key; + } + + cursor_move_right(wr); +} + /* libcurses version */ static gchar * @@ -126,14 +146,15 @@ _wreadln(WINDOW *w, GCompletion *gcmp, gboolean masked) { + struct wreadln wr = { + .w = w, + .masked = masked, + .cursor = 0, + .start = 0, + }; GList *hlist = NULL, *hcurrent = NULL; - gchar *line; - gint x0, y, width; - gint cursor = 0, start = 0; gint key = 0, i; - /* allocate a line buffer */ - line = g_malloc0(wrln_max_line_size); /* turn off echo */ noecho(); /* make shure the cursor is visible */ @@ -142,17 +163,17 @@ _wreadln(WINDOW *w, if (prompt) waddstr(w, prompt); /* retrive y and x0 position */ - getyx(w, y, x0); + getyx(w, wr.y, wr.x); /* check the x1 value */ - if (x1 <= x0 || x1 > COLS) + if (x1 <= wr.x || x1 > COLS) x1 = COLS; - width = x1 - x0; + wr.width = x1 - wr.x; /* clear input area */ - mvwhline(w, y, x0, ' ', width); + mvwhline(w, wr.y, wr.x, ' ', wr.width); if (history) { /* append the a new line to our history list */ - *history = g_list_append(*history, g_malloc0(wrln_max_line_size)); + *history = g_list_append(*history, g_malloc0(sizeof(wr.line))); /* hlist points to the current item in the history list */ hlist = g_list_last(*history); hcurrent = hlist; @@ -163,19 +184,19 @@ _wreadln(WINDOW *w, if (history && hlist->prev) { if (hlist == hcurrent) /* save the current line */ - g_strlcpy(hlist->data, line, wrln_max_line_size); + g_strlcpy(hlist->data, wr.line, sizeof(wr.line)); /* get previous line */ hlist = hlist->prev; - g_strlcpy(line, hlist->data, wrln_max_line_size); + g_strlcpy(wr.line, hlist->data, sizeof(wr.line)); } - cursor_move_to_eol(&cursor, &start, width, x0, x1, line); - drawline(cursor, start, width, x0, y, masked, line, w); + cursor_move_to_eol(&wr); + drawline(&wr); } else if (initial_value) { /* copy the initial value to the line buffer */ - g_strlcpy(line, initial_value, wrln_max_line_size); - cursor_move_to_eol(&cursor, &start, width, x0, x1, line); - drawline(cursor, start, width, x0, y, masked, line, w); + g_strlcpy(wr.line, initial_value, sizeof(wr.line)); + cursor_move_to_eol(&wr); + drawline(&wr); } while (key != 13 && key != '\n') { @@ -201,25 +222,24 @@ _wreadln(WINDOW *w, GList *list; if (wrln_pre_completion_callback) - wrln_pre_completion_callback(gcmp, line, + wrln_pre_completion_callback(gcmp, wr.line, wrln_completion_callback_data); - list = g_completion_complete(gcmp, line, &prefix); + list = g_completion_complete(gcmp, wr.line, &prefix); if (prefix) { - g_strlcpy(line, prefix, wrln_max_line_size); - cursor_move_to_eol(&cursor, &start, width, x0, x1, line); + g_strlcpy(wr.line, prefix, sizeof(wr.line)); + cursor_move_to_eol(&wr); g_free(prefix); } else screen_bell(); if (wrln_post_completion_callback) - wrln_post_completion_callback(gcmp, line, list, + wrln_post_completion_callback(gcmp, wr.line, list, wrln_completion_callback_data); } break; case KEY_CTRL_G: screen_bell(); - g_free(line); if (history) { g_free(hcurrent->data); hcurrent->data = NULL; @@ -229,44 +249,44 @@ _wreadln(WINDOW *w, case KEY_LEFT: case KEY_CTRL_B: - cursor_move_left(&cursor, &start); + cursor_move_left(&wr); break; case KEY_RIGHT: case KEY_CTRL_F: - cursor_move_right(&cursor, &start, width, x0, x1, line); + cursor_move_right(&wr); break; case KEY_HOME: case KEY_CTRL_A: - cursor = 0; - start = 0; + wr.cursor = 0; + wr.start = 0; break; case KEY_END: case KEY_CTRL_E: - cursor_move_to_eol(&cursor, &start, width, x0, x1, line); + cursor_move_to_eol(&wr); break; case KEY_CTRL_K: - line[cursor] = 0; + wr.line[wr.cursor] = 0; break; case KEY_CTRL_U: - cursor = utf8_width(line); - for (i = 0;i < cursor; i++) - line[i] = '\0'; - cursor = 0; + wr.cursor = utf8_width(wr.line); + for (i = 0; i < wr.cursor; i++) + wr.line[i] = '\0'; + wr.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(&cursor, &start); + if (wr.cursor > 0) {/* - 1 from buf[n+1] to buf */ + for (i = wr.cursor - 1; wr.line[i] != 0; i++) + wr.line[i] = wr.line[i + 1]; + cursor_move_left(&wr); } break; case KEY_DC: /* handle delete key. As above */ case KEY_CTRL_D: - if (cursor <= (gint)utf8_width(line) - 1) { - for (i = cursor; line[i] != 0; i++) - line[i] = line[i + 1]; + if (wr.cursor <= (gint)utf8_width(wr.line) - 1) { + for (i = wr.cursor; wr.line[i] != 0; i++) + wr.line[i] = wr.line[i + 1]; } break; case KEY_UP: @@ -275,13 +295,15 @@ _wreadln(WINDOW *w, if (history && hlist->prev) { if (hlist == hcurrent) /* save the current line */ - g_strlcpy(hlist->data, line, wrln_max_line_size); + g_strlcpy(hlist->data, wr.line, + sizeof(wr.line)); /* get previous line */ hlist = hlist->prev; - g_strlcpy(line, hlist->data, wrln_max_line_size); + g_strlcpy(wr.line, hlist->data, + sizeof(wr.line)); } - cursor_move_to_eol(&cursor, &start, width, x0, x1, line); + cursor_move_to_eol(&wr); break; case KEY_DOWN: case KEY_CTRL_N: @@ -289,9 +311,10 @@ _wreadln(WINDOW *w, if (history && hlist->next) { /* get next line */ hlist = hlist->next; - g_strlcpy(line, hlist->data, wrln_max_line_size); + g_strlcpy(wr.line, hlist->data, + sizeof(wr.line)); } - cursor_move_to_eol(&cursor, &start, width, x0, x1, line); + cursor_move_to_eol(&wr); break; case '\n': @@ -303,37 +326,20 @@ _wreadln(WINDOW *w, /* ignore char */ break; default: - if (key >= 32) { - if (strlen (line + cursor)) { /* if the cursor is */ - /* not at the last pos */ - gchar *tmp = NULL; - gsize size = strlen(line + cursor) + 1; - - tmp = g_malloc0(size); - g_strlcpy (tmp, line + cursor, size); - line[cursor] = key; - line[cursor + 1] = 0; - g_strlcat (&line[cursor + 1], tmp, size); - g_free(tmp); - cursor_move_right(&cursor, &start, width, x0, x1, line); - } else { - line[cursor + 1] = 0; - line[cursor] = key; - cursor_move_right(&cursor, &start, width, x0, x1, line); - } - } + if (key >= 32) + wreadln_insert_byte(&wr, key); } - drawline(cursor, start, width, x0, y, masked, line, w); + drawline(&wr); } /* update history */ if (history) { - if (strlen(line)) { + if (strlen(wr.line)) { /* update the current history entry */ - size_t size = strlen(line)+1; + size_t size = strlen(wr.line) + 1; hcurrent->data = g_realloc(hcurrent->data, size); - g_strlcpy(hcurrent->data, line, size); + g_strlcpy(hcurrent->data, wr.line, size); } else { /* the line was empty - remove the current history entry */ g_free(hcurrent->data); @@ -351,7 +357,7 @@ _wreadln(WINDOW *w, } } - return g_realloc(line, strlen(line)+1); + return g_strdup(wr.line); } gchar *