history.c (4761B)
1#include "list.h" 2#define _GNU_SOURCE 3 4#include "history.h" 5#include "util.h" 6 7#include "grapheme.h" 8 9#include <string.h> 10#include <stdlib.h> 11 12static struct inputln *history_list_prev( 13 struct inputln *cur, const char *search); 14 15static struct inputln *history_list_next( 16 struct inputln *cur, const char *search); 17 18struct inputln * 19history_list_prev(struct inputln *cur, const char *search) 20{ 21 struct list_link *iter; 22 struct inputln *ln; 23 24 for (iter = cur->link.prev; iter && iter->prev; iter = iter->prev) { 25 ln = LIST_UPCAST(iter, struct inputln, link); 26 if (!search || !*search || strcasestr(ln->buf, search)) 27 return ln; 28 } 29 30 return cur; 31} 32 33struct inputln * 34history_list_next(struct inputln *cur, const char *search) 35{ 36 struct list_link *iter; 37 struct inputln *ln; 38 39 iter = cur->link.next; 40 while (LIST_INNER(iter)) { 41 ln = LIST_UPCAST(iter, struct inputln, link); 42 if (!search || !*search || strcasestr(ln->buf, search)) 43 return ln; 44 iter = iter->next; 45 } 46 47 return cur; 48} 49 50void 51history_init(struct history *history) 52{ 53 list_init(&history->list); 54 history->input = inputln_alloc(); 55 history->sel = history->input; 56} 57 58void 59history_deinit(struct history *history) 60{ 61 struct list_link *link; 62 struct inputln *ln; 63 64 link = list_link_pop(&history->input->link); 65 ln = LIST_UPCAST(link, struct inputln, link); 66 inputln_free(ln); 67 history->input = NULL; 68 69 list_free_items(&history->list, (list_item_free_fn) inputln_free, 70 LIST_OFFSET(struct inputln, link)); 71 72 history->sel = NULL; 73} 74 75void 76history_submit(struct history *history) 77{ 78 /* if chose from history free input */ 79 if (history->sel != history->input) { 80 list_link_pop(&history->input->link); 81 inputln_free(history->input); 82 } 83 84 /* pop first in case already in history */ 85 list_link_pop(&history->sel->link); 86 history_add(history, history->sel); 87 88 /* create new input buf and add to hist */ 89 history->input = inputln_alloc(); 90 history->sel = history->input; 91 history_add(history, history->sel); 92} 93 94void 95history_prev(struct history *history) 96{ 97 history->sel = history_list_prev(history->sel, history->input->buf); 98} 99 100void 101history_next(struct history *history) 102{ 103 history->sel = history_list_next(history->sel, history->input->buf); 104} 105 106void 107history_add(struct history *history, struct inputln *line) 108{ 109 struct inputln *ln; 110 struct list_link *back; 111 112 if (list_len(&history->list) == HISTORY_MAX) { 113 /* pop last item to make space */ 114 back = list_pop_back(&history->list); 115 ln = LIST_UPCAST(back, struct inputln, link); 116 inputln_free(ln); 117 } 118 119 list_insert_front(&history->list, &line->link); 120} 121 122void 123inputln_init(struct inputln *ln) 124{ 125 ln->buf = NULL; 126 ln->len = 0; 127 ln->cap = 0; 128 ln->cur = 0; 129 ln->curpos = 0; 130 ln->link = LIST_LINK_INIT; 131 132 inputln_resize(ln, 128); 133} 134 135void 136inputln_deinit(struct inputln *ln) 137{ 138 free(ln->buf); 139} 140 141struct inputln * 142inputln_alloc(void) 143{ 144 struct inputln *ln; 145 146 ln = malloc(sizeof(struct inputln)); 147 if (!ln) ERROR(SYSTEM, "malloc"); 148 inputln_init(ln); 149 150 return ln; 151} 152 153void 154inputln_free(struct inputln *ln) 155{ 156 inputln_deinit(ln); 157 free(ln); 158} 159 160void 161inputln_resize(struct inputln *ln, size_t size) 162{ 163 ASSERT(size != 0); 164 165 ln->cap = size; 166 ln->buf = realloc(ln->buf, ln->cap * sizeof(char)); 167 if (!ln->buf) ERROR(SYSTEM, "realloc"); 168 ln->len = MIN(ln->len, ln->cap-1); 169 ln->buf[ln->len] = '\0'; 170} 171 172void 173inputln_left(struct inputln *ln) 174{ 175 ln->cur = utf8_next_break_left(ln->buf, ln->cur); 176 ln->curpos = text_width(ln->buf, ln->cur); 177} 178 179void 180inputln_right(struct inputln *ln) 181{ 182 ln->cur = utf8_next_break_right(ln->buf, ln->cur); 183 ln->curpos = text_width(ln->buf, ln->cur); 184} 185 186void 187inputln_addch(struct inputln *ln, char c) 188{ 189 int i; 190 191 if (ln->len + 1 >= ln->cap) { 192 ln->cap *= 2; 193 ln->buf = realloc(ln->buf, ln->cap); 194 } 195 196 for (i = ln->len; i > ln->cur; i--) 197 ln->buf[i] = ln->buf[i-1]; 198 ln->buf[ln->cur] = c; 199 200 ln->len++; 201 ln->cur++; 202 ln->buf[ln->len] = '\0'; 203 204 ln->curpos = text_width(ln->buf, ln->cur); 205} 206 207void 208inputln_del(struct inputln *ln, int n) 209{ 210 size_t next; 211 int i; 212 213 if (!ln->cur) return; 214 215 next = utf8_next_break_left(ln->buf, ln->cur); 216 n = ln->cur - next; 217 for (i = ln->cur; i <= ln->len; i++) 218 ln->buf[i-n] = ln->buf[i]; 219 220 ln->len -= n; 221 ln->cur -= n; 222 ln->buf[ln->len] = '\0'; 223 224 ln->curpos = text_width(ln->buf, ln->cur); 225} 226 227void 228inputln_copy(struct inputln *dst, struct inputln *src) 229{ 230 if (dst->buf) { 231 free(dst->buf); 232 dst->buf = NULL; 233 } 234 dst->len = src->len; 235 dst->buf = astrdup(src->buf); 236 dst->cap = src->len + 1; 237 dst->cur = dst->len; 238 dst->curpos = text_width(dst->buf, dst->len); 239} 240 241void 242inputln_replace(struct inputln *ln, const char *str) 243{ 244 ln->len = strlen(str); 245 if (ln->cap <= ln->len) 246 inputln_resize(ln, ln->len + 1); 247 strncpy(ln->buf, str, ln->len + 1); 248 ln->cur = ln->len; 249 ln->curpos = text_width(ln->buf, ln->len); 250} 251