@@ 13,6 13,8 @@
#error INPUT_HIST_MAX must be a power of 2
#endif
+#define INPUT_HIST_LINE(I, X) ((I)->hist.ptrs[INPUT_MASK((X))])
+
static char *input_text_copy(struct input*);
static int input_text_isfull(struct input*);
static int input_text_iszero(struct input*);
@@ 30,10 32,8 @@ input_init(struct input *inp)
void
input_free(struct input *inp)
{
- free(inp->hist.save);
-
while (inp->hist.tail != inp->hist.head)
- free(inp->hist.ptrs[INPUT_MASK(inp->hist.tail++)]);
+ free(INPUT_HIST_LINE(inp, inp->hist.tail++));
}
int
@@ 42,7 42,7 @@ input_cursor_back(struct input *inp)
if (inp->head == 0)
return 0;
- inp->text[--inp->tail] = inp->text[--inp->head];
+ inp->buf[--inp->tail] = inp->buf[--inp->head];
return 1;
}
@@ 53,7 53,7 @@ input_cursor_forw(struct input *inp)
if (inp->tail == INPUT_LEN_MAX)
return 0;
- inp->text[inp->head++] = inp->text[inp->tail++];
+ inp->buf[inp->head++] = inp->buf[inp->tail++];
return 1;
}
@@ 89,10 89,10 @@ input_insert(struct input *inp, const char *c, size_t count)
while (!input_text_isfull(inp) && count--) {
if (iscntrl(*c))
- inp->text[inp->head++] = ' ';
+ inp->buf[inp->head++] = ' ';
if (isprint(*c))
- inp->text[inp->head++] = *c;
+ inp->buf[inp->head++] = *c;
c++;
}
@@ 106,11 106,7 @@ input_reset(struct input *inp)
if (input_text_iszero(inp))
return 0;
- free(inp->hist.save);
-
inp->hist.current = inp->hist.head;
- inp->hist.save = NULL;
-
inp->head = 0;
inp->tail = INPUT_LEN_MAX;
inp->window = 0;
@@ 134,17 130,17 @@ input_complete(struct input *inp, f_completion_cb cb)
head = inp->head;
tail = inp->tail;
- while (head && inp->text[head - 1] != ' ')
+ while (head && inp->buf[head - 1] != ' ')
head--;
- if (inp->text[head] == ' ')
+ if (inp->buf[head] == ' ')
return 0;
- while (tail < INPUT_LEN_MAX && inp->text[tail] != ' ')
+ while (tail < INPUT_LEN_MAX && inp->buf[tail] != ' ')
tail++;
ret = (*cb)(
- (inp->text + head),
+ (inp->buf + head),
(inp->head - head - inp->tail + tail),
(INPUT_LEN_MAX - input_text_size(inp)),
(head == 0));
@@ 165,17 161,10 @@ input_hist_back(struct input *inp)
if (input_hist_size(inp) == 0 || inp->hist.current == inp->hist.tail)
return 0;
- if (inp->hist.current == inp->hist.head) {
- inp->hist.save = input_text_copy(inp);
- } else {
- free(inp->hist.ptrs[INPUT_MASK(inp->hist.current)]);
- inp->hist.ptrs[INPUT_MASK(inp->hist.current)] = input_text_copy(inp);
- }
-
inp->hist.current--;
- len = strlen(inp->hist.ptrs[INPUT_MASK(inp->hist.current)]);
- memcpy(inp->text, inp->hist.ptrs[INPUT_MASK(inp->hist.current)], len);
+ len = strlen(INPUT_HIST_LINE(inp, inp->hist.current));
+ memcpy(inp->buf, INPUT_HIST_LINE(inp, inp->hist.current), len);
inp->head = len;
inp->tail = INPUT_LEN_MAX;
@@ 186,30 175,18 @@ input_hist_back(struct input *inp)
int
input_hist_forw(struct input *inp)
{
- char *str;
- size_t len = 0;
+ size_t len;
if (input_hist_size(inp) == 0 || inp->hist.current == inp->hist.head)
return 0;
- free(inp->hist.ptrs[INPUT_MASK(inp->hist.current)]);
- inp->hist.ptrs[INPUT_MASK(inp->hist.current)] = input_text_copy(inp);
-
inp->hist.current++;
- if (inp->hist.current == inp->hist.head)
- str = inp->hist.save;
- else
- str = inp->hist.ptrs[INPUT_MASK(inp->hist.current)];
-
- if (str) {
- len = strlen(str);
- memcpy(inp->text, str, len);
- }
-
if (inp->hist.current == inp->hist.head) {
- free(inp->hist.save);
- inp->hist.save = NULL;
+ len = 0;
+ } else {
+ len = strlen(INPUT_HIST_LINE(inp, inp->hist.current));
+ memcpy(inp->buf, INPUT_HIST_LINE(inp, inp->hist.current), len);
}
inp->head = len;
@@ 221,32 198,15 @@ input_hist_forw(struct input *inp)
int
input_hist_push(struct input *inp)
{
- char *save;
+ char *hist;
- if ((save = input_text_copy(inp)) == NULL)
+ if ((hist = input_text_copy(inp)) == NULL)
return 0;
- if (inp->hist.current < inp->hist.head) {
-
- uint16_t i;
-
- free(inp->hist.ptrs[INPUT_MASK(inp->hist.current)]);
-
- for (i = inp->hist.current; i < inp->hist.head - 1; i++)
- inp->hist.ptrs[INPUT_MASK(i)] = inp->hist.ptrs[INPUT_MASK(i + 1)];
+ if (input_hist_size(inp) == INPUT_HIST_MAX)
+ free(INPUT_HIST_LINE(inp, inp->hist.tail++));
- inp->hist.current = i;
- inp->hist.ptrs[INPUT_MASK(inp->hist.current)] = save;
-
- } else if (input_hist_size(inp) == INPUT_HIST_MAX) {
-
- free(inp->hist.ptrs[INPUT_MASK(inp->hist.tail++)]);
- inp->hist.ptrs[INPUT_MASK(inp->hist.head++)] = save;
-
- } else {
-
- inp->hist.ptrs[INPUT_MASK(inp->hist.head++)] = save;
- }
+ INPUT_HIST_LINE(inp, inp->hist.head++) = hist;
return input_reset(inp);
}
@@ 289,14 249,14 @@ input_write(struct input *inp, char *buf, uint16_t max, uint16_t pos)
uint16_t buf_len = 0;
while (max > 1 && pos < inp->head) {
- buf[buf_len++] = inp->text[pos++];
+ buf[buf_len++] = inp->buf[pos++];
max--;
}
pos = inp->tail;
while (max > 1 && pos < INPUT_LEN_MAX) {
- buf[buf_len++] = inp->text[pos++];
+ buf[buf_len++] = inp->buf[pos++];
max--;
}
@@ 161,7 161,7 @@ test_input_del(void)
input_init(&inp);
- /* Deleting back/forw on empty input */
+ /* Deleting back/forward on empty input */
CHECK_INPUT_WRITE(&inp, "");
assert_eq(input_delete_back(&inp), 0);
assert_eq(input_delete_forw(&inp), 0);
@@ 220,24 220,23 @@ test_input_hist(void)
assert_eq(input_insert(&inp, "444", 3), 1);
assert_eq(input_hist_push(&inp), 1);
-#define INP_HIST_CURR(I) ((I).hist.ptrs[INPUT_MASK((I).hist.current)])
-#define INP_HIST_HEAD(I) ((I).hist.ptrs[INPUT_MASK((I).hist.head - 1)])
-#define INP_HIST_TAIL(I) ((I).hist.ptrs[INPUT_MASK((I).hist.tail)])
-
- assert_strcmp(INP_HIST_HEAD(inp), "444");
- assert_strcmp(INP_HIST_TAIL(inp), "111");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "444");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.tail), "111");
/* Test pushing after INPUT_HIST_MAX frees the tail */
assert_eq(input_insert(&inp, "555", 3), 1);
assert_eq(input_hist_push(&inp), 1);
- assert_strcmp(INP_HIST_HEAD(inp), "555");
- assert_strcmp(INP_HIST_TAIL(inp), "222");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "555");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.tail), "222");
- /* Test scrolling back saves the current working input */
- assert_eq(input_insert(&inp, "000", 3), 1);
+ /* Test scrolling backwards */
+ assert_eq(input_reset(&inp), 0);
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 4), "222");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 3), "333");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 2), "444");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "555");
- /* Test scrolling back to tail */
assert_eq(input_hist_back(&inp), 1);
CHECK_INPUT_WRITE(&inp, "555");
assert_eq(input_hist_back(&inp), 1);
@@ 247,9 246,9 @@ test_input_hist(void)
assert_eq(input_hist_back(&inp), 1);
CHECK_INPUT_WRITE(&inp, "222");
assert_eq(input_hist_back(&inp), 0);
- assert_strcmp(inp.hist.save, "000");
+ CHECK_INPUT_WRITE(&inp, "222");
- /* Test scrolling forw to head */
+ /* Test scrolling forwards */
assert_eq(input_hist_forw(&inp), 1);
CHECK_INPUT_WRITE(&inp, "333");
assert_eq(input_hist_forw(&inp), 1);
@@ 257,38 256,51 @@ test_input_hist(void)
assert_eq(input_hist_forw(&inp), 1);
CHECK_INPUT_WRITE(&inp, "555");
assert_eq(input_hist_forw(&inp), 1);
- CHECK_INPUT_WRITE(&inp, "000");
+ CHECK_INPUT_WRITE(&inp, "");
assert_eq(input_hist_forw(&inp), 0);
+ CHECK_INPUT_WRITE(&inp, "");
- assert_strcmp(INP_HIST_HEAD(inp), "555");
- assert_strcmp(INP_HIST_TAIL(inp), "222");
+ /* Test replaying history */
+ assert_eq(input_reset(&inp), 0);
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 4), "222");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 3), "333");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 2), "444");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "555");
- /* Test replaying hist head */
+ /* Test replaying history from head */
assert_eq(input_hist_back(&inp), 1);
assert_eq(input_hist_push(&inp), 1);
- assert_strcmp(INP_HIST_HEAD(inp), "555");
- assert_strcmp(INP_HIST_TAIL(inp), "222");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 4), "333");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 3), "444");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 2), "555");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "555");
- /* Test replaying hist middle */
+ /* Test replaying history from tail */
assert_eq(input_hist_back(&inp), 1);
assert_eq(input_hist_back(&inp), 1);
+ assert_eq(input_hist_back(&inp), 1);
+ assert_eq(input_hist_back(&inp), 1);
+ assert_eq(input_hist_back(&inp), 0);
assert_eq(input_hist_push(&inp), 1);
- assert_strcmp(INP_HIST_HEAD(inp), "444");
- assert_strcmp(INP_HIST_TAIL(inp), "222");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 4), "444");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 3), "555");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 2), "555");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "333");
- /* Test replaying hist tail */
+ /* Test replaying history with edit */
assert_eq(input_hist_back(&inp), 1);
assert_eq(input_hist_back(&inp), 1);
assert_eq(input_hist_back(&inp), 1);
- assert_eq(input_hist_back(&inp), 1);
- assert_eq(input_hist_back(&inp), 0);
+ assert_eq(input_insert(&inp, "xxx", 3), 1);
assert_eq(input_hist_push(&inp), 1);
- assert_strcmp(INP_HIST_HEAD(inp), "222");
- assert_strcmp(INP_HIST_TAIL(inp), "333");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 4), "555");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 3), "555");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 2), "333");
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "555xxx");
-#undef INP_HIST_CURR
-#undef INP_HIST_HEAD
-#undef INP_HIST_TAIL
+ /* Test pushing resets scrollback */
+ assert_eq(input_hist_back(&inp), 1);
+ assert_strcmp(INPUT_HIST_LINE(&inp, inp.hist.head - 1), "555xxx");
input_free(&inp);
}
@@ 361,7 373,7 @@ test_input_frame(void)
assert_eq(input_cursor_back(&inp), 1);
CHECK_INPUT_FRAME(&inp, "12345", 6, 0);
- /* Test cursor forw keeps cursor in view */
+ /* Test cursor forward keeps cursor in view */
assert_eq(input_cursor_forw(&inp), 1);
assert_eq(input_cursor_forw(&inp), 1);
assert_eq(input_cursor_forw(&inp), 1);
@@ 439,26 451,26 @@ test_input_complete(void)
/* Test: ` abc `
* ^ */
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
assert_eq(input_complete(&inp, completion_rot1), 1);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
CHECK_INPUT_WRITE(&inp, " bcd ");
/* Test: ` bcd `
* ^ */
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], 'd');
+ assert_eq(inp.buf[inp.head], 'd');
assert_eq(input_complete(&inp, completion_rot1), 1);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
CHECK_INPUT_WRITE(&inp, " cde ");
/* Test: ` cde `
* ^ */
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], 'd');
+ assert_eq(inp.buf[inp.head], 'd');
assert_eq(input_complete(&inp, completion_rot1), 1);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
CHECK_INPUT_WRITE(&inp, " def ");
/* Test: ` def `
@@ 466,9 478,9 @@ test_input_complete(void)
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], 'd');
+ assert_eq(inp.buf[inp.head], 'd');
assert_eq(input_complete(&inp, completion_rot1), 1);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
CHECK_INPUT_WRITE(&inp, " efg ");
/* Test: ` efg `
@@ 477,9 489,9 @@ test_input_complete(void)
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
assert_eq(input_complete(&inp, completion_rot1), 0);
- assert_eq(inp.text[inp.head], ' ');
+ assert_eq(inp.buf[inp.head], ' ');
CHECK_INPUT_WRITE(&inp, " efg ");
assert_eq(input_reset(&inp), 1);
@@ 491,9 503,9 @@ test_input_complete(void)
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], 'x');
+ assert_eq(inp.buf[inp.head], 'x');
assert_eq(input_complete(&inp, completion_rot1), 1);
- assert_eq(inp.text[inp.tail], ' ');
+ assert_eq(inp.buf[inp.tail], ' ');
CHECK_INPUT_WRITE(&inp, "y!! abc ");
assert_eq(input_reset(&inp), 1);
@@ 503,10 515,10 @@ test_input_complete(void)
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], 'c');
+ assert_eq(inp.buf[inp.head], 'c');
assert_eq(input_complete(&inp, completion_l), 1);
CHECK_INPUT_WRITE(&inp, " xyxyxy ab");
- assert_eq(inp.text[inp.tail], ' '); /* points to 'c' */
+ assert_eq(inp.buf[inp.tail], ' '); /* points to 'c' */
assert_eq(input_reset(&inp), 1);
/* Test replacement word shorter */
@@ 516,10 528,10 @@ test_input_complete(void)
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
assert_eq(input_cursor_back(&inp), 1);
- assert_eq(inp.text[inp.head], 'c');
+ assert_eq(inp.buf[inp.head], 'c');
assert_eq(input_complete(&inp, completion_s), 1);
CHECK_INPUT_WRITE(&inp, " z ab ");
- assert_eq(inp.text[inp.tail], ' ');
+ assert_eq(inp.buf[inp.tail], ' ');
assert_eq(input_reset(&inp), 1);
/* Test writing up to max chars */