mirror of https://github.com/ericonr/ef.git
Rework the list so navigating with arrows fully works.
It's still necessary to fix display after a query, but the current navigation should just work when that's added.
This commit is contained in:
parent
1e42b5527e
commit
7385d08bf1
123
browser.c
123
browser.c
|
@ -71,13 +71,39 @@ int main()
|
||||||
init_pair(1, COLOR_GREEN, COLOR_BLACK);
|
init_pair(1, COLOR_GREEN, COLOR_BLACK);
|
||||||
// red,green,yellow,blue,cyan,magenta,white
|
// red,green,yellow,blue,cyan,magenta,white
|
||||||
}
|
}
|
||||||
/* noop function - should use the windows from below */
|
int cattr = COLOR_PAIR(1) | A_BOLD;
|
||||||
attrset(COLOR_PAIR(1));
|
int nattr = A_NORMAL;
|
||||||
|
|
||||||
|
/* list should work as follows:
|
||||||
|
* - can fit up to entries.n
|
||||||
|
* - element 0 is at the bottom (entries.n - 1)
|
||||||
|
* - last element is at the top (0)
|
||||||
|
*/
|
||||||
|
|
||||||
/* store number of rows that can be displayed in list */
|
/* store number of rows that can be displayed in list */
|
||||||
const int nrows = LINES - 1;
|
const int nrows = LINES - 1;
|
||||||
|
/* list position in x and y;
|
||||||
|
* listx currently isn't changed anywhere */
|
||||||
|
int listy;
|
||||||
|
const int listx = 0;
|
||||||
|
/* current pick */
|
||||||
|
size_t pick = 0;
|
||||||
|
/* list size */
|
||||||
|
int listsize;
|
||||||
|
|
||||||
WINDOW *list = newpad(entries.n, COLS);
|
if (entries.n <= (size_t)nrows) {
|
||||||
|
/* list should be at least as big as nrows */
|
||||||
|
listsize = nrows;
|
||||||
|
|
||||||
|
listy = 0;
|
||||||
|
} else {
|
||||||
|
listsize = entries.n;
|
||||||
|
|
||||||
|
/* move to position where we show the end of the list */
|
||||||
|
listy = entries.n - nrows;
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOW *list = newpad(listsize, COLS);
|
||||||
WINDOW *prompt = newwin(1, 0, LINES - 1, 0);
|
WINDOW *prompt = newwin(1, 0, LINES - 1, 0);
|
||||||
if (!list || !prompt) {
|
if (!list || !prompt) {
|
||||||
perror("newwin");
|
perror("newwin");
|
||||||
|
@ -85,20 +111,24 @@ int main()
|
||||||
}
|
}
|
||||||
keypad(prompt, TRUE);
|
keypad(prompt, TRUE);
|
||||||
|
|
||||||
/* inital dump of list */
|
/* initial prompt */
|
||||||
for (size_t i = 0; i < entries.n; i++) {
|
|
||||||
mvwaddstr(list, i, 0, get_entry(&entries, i));
|
|
||||||
}
|
|
||||||
prefresh(list, 0, 0, 0, 0, nrows - 1, COLS);
|
|
||||||
|
|
||||||
mvwaddstr(prompt, 0, 0, "> ");
|
mvwaddstr(prompt, 0, 0, "> ");
|
||||||
wrefresh(prompt);
|
wrefresh(prompt);
|
||||||
|
|
||||||
struct str_array toks = { 0 };
|
#define WRITELIST(idx) mvwaddstr(list, listsize - idx - 1, 0, get_entry(&entries, idx))
|
||||||
|
/* inital dump of list */
|
||||||
|
for (size_t i = 0; i < entries.n; i++) {
|
||||||
|
if (i == pick) wattrset(list, cattr);
|
||||||
|
WRITELIST(i);
|
||||||
|
if (i == pick) wattrset(list, nattr);
|
||||||
|
}
|
||||||
|
prefresh(list, listy, listx, 0, 0, nrows-1, COLS);
|
||||||
|
|
||||||
|
/* variables to control current search token */
|
||||||
size_t n, cap;
|
size_t n, cap;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
/* listx isn't changed anywhere */
|
/* search tokens */
|
||||||
int listx = 0, listy = 0;
|
struct str_array toks = { 0 };
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
cap = 1024;
|
cap = 1024;
|
||||||
|
@ -109,62 +139,53 @@ int main()
|
||||||
add_entry(&toks, name);
|
add_entry(&toks, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool name_changed = false;
|
int pos_change = 0;
|
||||||
int c = wgetch(prompt);
|
int c = wgetch(prompt);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
/* Ctrl+[ or ESC */
|
case 27: /* Ctrl+[ or ESC */
|
||||||
case 27:
|
|
||||||
exit(1);
|
exit(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_ENTER:
|
case KEY_ENTER:
|
||||||
case '\r':
|
case '\r':
|
||||||
/* since we are using nonl above, only capture '\r' itself
|
/* since we are using nonl above, only capture '\r' itself */
|
||||||
* TODO: actually store the entry name */
|
final_name = get_entry(&entries, pick);
|
||||||
final_name = name;
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
case KEY_DOWN:
|
case KEY_DOWN:
|
||||||
/* Ctrl-N */
|
case 14: /* Ctrl-N */
|
||||||
case 14:
|
pos_change = -1;
|
||||||
if ((size_t)listy < entries.n && (size_t)nrows < entries.ms ) listy++;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_UP:
|
case KEY_UP:
|
||||||
/* Ctrl-P */
|
case 16: /* Ctrl-P */
|
||||||
case 16:
|
pos_change = +1;
|
||||||
if (listy) listy--;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Ctrl+W */
|
/* TODO: treat n==0 */
|
||||||
case 23:
|
case 23: /* Ctrl+W */
|
||||||
n = 0;
|
n = 0;
|
||||||
name[n] = 0;
|
name[n] = 0;
|
||||||
name_changed = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_BACKSPACE:
|
case KEY_BACKSPACE:
|
||||||
/* DEL */
|
case 127: /* DEL */
|
||||||
case 127:
|
|
||||||
/* go back to previous word */
|
/* go back to previous word */
|
||||||
if (toks.n > 1 && n == 0) {
|
if (toks.n > 1 && n == 0) {
|
||||||
free(pop_entry(&toks));
|
free(pop_entry(&toks));
|
||||||
name = get_entry(&toks, toks.n - 1);
|
name = get_entry(&toks, toks.n - 1);
|
||||||
cap = malloc_usable_size(name);
|
cap = malloc_usable_size(name);
|
||||||
n = strlen(name);
|
n = strlen(name);
|
||||||
name_changed = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (n) n--;
|
if (n) n--;
|
||||||
name[n] = 0;
|
name[n] = 0;
|
||||||
name_changed = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
if (*name) {
|
if (*name) {
|
||||||
name = NULL;
|
name = NULL;
|
||||||
}
|
}
|
||||||
name_changed = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -176,11 +197,45 @@ int main()
|
||||||
n++;
|
n++;
|
||||||
/* clear chars from previous entries and/or dirty memory */
|
/* clear chars from previous entries and/or dirty memory */
|
||||||
name[n] = 0;
|
name[n] = 0;
|
||||||
name_changed = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!name_changed) {
|
|
||||||
|
if (pos_change) {
|
||||||
|
const size_t old_pick = pick;
|
||||||
|
/* XXX: trusting integer overflow to work things out here */
|
||||||
|
for (size_t i = pick + pos_change; i < entries.n; i += pos_change) {
|
||||||
|
if (get_entry_match(&entries, i)) {
|
||||||
|
pick = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pick == old_pick) continue;
|
||||||
|
|
||||||
|
/* clean up appearance */
|
||||||
|
wattrset(list, nattr);
|
||||||
|
WRITELIST(old_pick);
|
||||||
|
wattrset(list, cattr);
|
||||||
|
WRITELIST(pick);
|
||||||
|
wattrset(list, nattr);
|
||||||
|
|
||||||
|
/* find index inside set of matches */
|
||||||
|
size_t index_in_matched = 0;
|
||||||
|
for (size_t i = 0; i < pick; i++) {
|
||||||
|
if (get_entry_match(&entries, i)) index_in_matched++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if all matched entries fit in visible list */
|
||||||
|
if (entries.ms <= (size_t)nrows) {
|
||||||
|
/* pass */
|
||||||
|
} else {
|
||||||
|
/* check if pick is above or below */
|
||||||
|
const size_t bottom = (entries.ms) - (listy+nrows);
|
||||||
|
const size_t top = bottom + nrows - 1;
|
||||||
|
if (index_in_matched < bottom) listy++;
|
||||||
|
else if (index_in_matched > top) listy--;
|
||||||
|
}
|
||||||
prefresh(list, listy, listx, 0, 0, nrows-1, COLS);
|
prefresh(list, listy, listx, 0, 0, nrows-1, COLS);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue