Add support for el_bind_key() and example usage binding '?' in examples/cli.c

This changeset refactors el_bind_key_in_metamap() into two functions,
adding el_bind_key(), to provide the ability for the user to bind keys
in both the regular and the meta-key maps.

Several useful, but previously internal, functions have been made global to
facilitate the example code mentioned above. These are likely useful to the
user of this library as well:

  el_print_columns() - Display words in columns across a tty_cols wide screen.
  el_ring_bell()     - Can be used as default key binding function.
  el_find_word()     - Returns a copy of the word at rl_point.
This commit is contained in:
Joachim Nilsson 2010-08-05 12:48:51 +02:00
parent 27fcc878a1
commit 5e9177fd18
5 changed files with 86 additions and 43 deletions

2
TODO
View File

@ -1,7 +1,7 @@
TODO TODO
* Port "fileman" example from BSD libedit, http://www.thrysoee.dk/editline/ * Port "fileman" example from BSD libedit, http://www.thrysoee.dk/editline/
* Add support for rl_bind_key(), currently one needs to "hack" the Map[] * Add support for rl_bind_key(), currently only en editline specific el_bind_key() exists.
* Add support for inhibiting completion: rl_inhibit_completion * Add support for inhibiting completion: rl_inhibit_completion
* Make "char *rl_prompt" globally visible. * Make "char *rl_prompt" globally visible.
* Add support for rl_set_prompt(). * Add support for rl_set_prompt().

View File

@ -80,6 +80,28 @@ static int my_rl_list_possib(char *token, char ***av)
return total; return total;
} }
el_status_t list_possible(void)
{
char **av;
char *word;
int ac;
word = el_find_word();
ac = rl_list_possib(word, &av);
if (word)
free(word);
if (ac) {
el_print_columns(ac, av);
while (--ac >= 0)
free(av[ac]);
free(av);
return CSmove;
}
return el_ring_bell();
}
int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused))) int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused)))
{ {
char *line; char *line;
@ -88,6 +110,7 @@ int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused)))
/* Setup callbacks */ /* Setup callbacks */
rl_set_complete_func(&my_rl_complete); rl_set_complete_func(&my_rl_complete);
rl_set_list_possib_func(&my_rl_list_possib); rl_set_list_possib_func(&my_rl_list_possib);
el_bind_key('?', list_possible);
read_history(HISTORY); read_history(HISTORY);
while ((line = readline(prompt)) != NULL) { while ((line = readline(prompt)) != NULL) {

View File

@ -39,7 +39,15 @@ typedef void rl_vintfunc_t(int);
extern int rl_meta_chars; extern int rl_meta_chars;
/* Editline specific functions. */ /* Editline specific functions. */
void el_bind_key_in_metamap(char c, el_keymap_func_t func); extern char * el_find_word(void);
extern void el_print_columns(int ac, char **av);
extern el_status_t el_ring_bell(void);
extern void el_bind_key(int key, el_keymap_func_t function);
extern void el_bind_key_in_metamap(int key, el_keymap_func_t function);
extern char *rl_complete(char *token, int *match);
extern int rl_list_possib(char *token, char ***av);
/* For compatibility with FSF readline. */ /* For compatibility with FSF readline. */
extern int rl_point; extern int rl_point;

View File

@ -309,7 +309,7 @@ void rl_deprep_terminal(void)
/* /*
** Print an array of words in columns. ** Print an array of words in columns.
*/ */
static void columns(int ac, char **av) void el_print_columns(int ac, char **av)
{ {
char *p; char *p;
int i; int i;
@ -374,7 +374,7 @@ static void right(el_status_t Change)
rl_point++; rl_point++;
} }
static el_status_t ring_bell(void) el_status_t el_ring_bell(void)
{ {
tty_put('\07'); tty_put('\07');
tty_flush(); tty_flush();
@ -392,7 +392,7 @@ static el_status_t do_macro(int c)
if ((el_input = (char *)getenv((char *)name)) == NULL) { if ((el_input = (char *)getenv((char *)name)) == NULL) {
el_input = NILSTR; el_input = NILSTR;
return ring_bell(); return el_ring_bell();
} }
return CSstay; return CSstay;
} }
@ -563,7 +563,7 @@ static const char *prev_hist(void)
static el_status_t do_insert_hist(const char *p) static el_status_t do_insert_hist(const char *p)
{ {
if (p == NULL) if (p == NULL)
return ring_bell(); return el_ring_bell();
rl_point = 0; rl_point = 0;
reposition(); reposition();
@ -581,7 +581,7 @@ static el_status_t do_hist(const char *(*move)(void))
i = 0; i = 0;
do { do {
if ((p = move()) == NULL) if ((p = move()) == NULL)
return ring_bell(); return el_ring_bell();
} while (++i < Repeat); } while (++i < Repeat);
return do_insert_hist(p); return do_insert_hist(p);
} }
@ -668,7 +668,7 @@ static el_status_t h_search(void)
const char *p; const char *p;
if (Searching) if (Searching)
return ring_bell(); return el_ring_bell();
Searching = 1; Searching = 1;
clear_line(); clear_line();
@ -688,7 +688,7 @@ static el_status_t h_search(void)
p = search_hist(p, move); p = search_hist(p, move);
clear_line(); clear_line();
if (p == NULL) { if (p == NULL) {
ring_bell(); el_ring_bell();
return redisplay(); return redisplay();
} }
return do_insert_hist(p); return do_insert_hist(p);
@ -730,7 +730,7 @@ static el_status_t delete_string(int count)
char *p; char *p;
if (count <= 0 || rl_end == rl_point) if (count <= 0 || rl_end == rl_point)
return ring_bell(); return el_ring_bell();
if (count == 1 && rl_point == rl_end - 1) { if (count == 1 && rl_point == rl_end - 1) {
/* Optimize common case of delete at end of line. */ /* Optimize common case of delete at end of line. */
@ -894,7 +894,7 @@ static el_status_t meta(void)
break; break;
} }
return ring_bell(); return el_ring_bell();
} }
#endif /* CONFIG_ANSI_ARROWS */ #endif /* CONFIG_ANSI_ARROWS */
@ -912,7 +912,7 @@ static el_status_t meta(void)
return kp->Function(); return kp->Function();
} }
return ring_bell(); return el_ring_bell();
} }
static el_status_t emacs(int c) static el_status_t emacs(int c)
@ -1231,7 +1231,7 @@ int write_history(const char *filename)
** Move back to the beginning of the current word and return an ** Move back to the beginning of the current word and return an
** allocated copy of it. ** allocated copy of it.
*/ */
static char *find_word(void) char *el_find_word(void)
{ {
char *p, *q; char *p, *q;
char *new; char *new;
@ -1274,12 +1274,12 @@ static el_status_t c_possible(void)
char *word; char *word;
int ac; int ac;
word = find_word(); word = el_find_word();
ac = rl_list_possib(word, &av); ac = rl_list_possib(word, &av);
if (word) if (word)
free(word); free(word);
if (ac) { if (ac) {
columns(ac, av); el_print_columns(ac, av);
while (--ac >= 0) while (--ac >= 0)
free(av[ac]); free(av[ac]);
free(av); free(av);
@ -1287,7 +1287,7 @@ static el_status_t c_possible(void)
return CSmove; return CSmove;
} }
return ring_bell(); return el_ring_bell();
} }
static el_status_t c_complete(void) static el_status_t c_complete(void)
@ -1298,7 +1298,7 @@ static el_status_t c_complete(void)
int unique; int unique;
el_status_t s = 0; el_status_t s = 0;
word = find_word(); word = el_find_word();
p = (char *)rl_complete((char *)word, &unique); p = (char *)rl_complete((char *)word, &unique);
if (word) if (word)
free(word); free(word);
@ -1321,7 +1321,7 @@ static el_status_t c_complete(void)
s = insert_string(new); s = insert_string(new);
#ifdef CONFIG_ANNOYING_NOISE #ifdef CONFIG_ANNOYING_NOISE
if (!unique) if (!unique)
ring_bell(); el_ring_bell();
#endif #endif
} }
free(new); free(new);
@ -1380,7 +1380,7 @@ static el_status_t exchange(void)
int c; int c;
if ((c = tty_get()) != CTL('X')) if ((c = tty_get()) != CTL('X'))
return c == EOF ? CSeof : ring_bell(); return c == EOF ? CSeof : el_ring_bell();
if ((c = rl_mark) <= rl_end) { if ((c = rl_mark) <= rl_end) {
rl_mark = rl_point; rl_mark = rl_point;
@ -1400,7 +1400,7 @@ static el_status_t yank(void)
static el_status_t copy_region(void) static el_status_t copy_region(void)
{ {
if (rl_mark > rl_end) if (rl_mark > rl_end)
return ring_bell(); return el_ring_bell();
if (rl_point > rl_mark) if (rl_point > rl_mark)
save_yank(rl_mark, rl_point - rl_mark); save_yank(rl_mark, rl_point - rl_mark);
@ -1526,14 +1526,14 @@ static el_status_t last_argument(void)
int ac; int ac;
if (H.Size == 1 || (p = (char *)H.Lines[H.Size - 2]) == NULL) if (H.Size == 1 || (p = (char *)H.Lines[H.Size - 2]) == NULL)
return ring_bell(); return el_ring_bell();
if ((p = strdup(p)) == NULL) if ((p = strdup(p)) == NULL)
return CSstay; return CSstay;
ac = argify(p, &av); ac = argify(p, &av);
if (Repeat != NO_ARG) if (Repeat != NO_ARG)
s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); s = Repeat < ac ? insert_string(av[Repeat]) : el_ring_bell();
else else
s = ac ? insert_string(av[ac - 1]) : CSstay; s = ac ? insert_string(av[ac - 1]) : CSstay;
@ -1544,14 +1544,14 @@ static el_status_t last_argument(void)
return s; return s;
} }
static el_keymap_t Map[33] = { static el_keymap_t Map[64] = {
{ CTL('@'), mk_set }, { CTL('@'), mk_set },
{ CTL('A'), beg_line }, { CTL('A'), beg_line },
{ CTL('B'), bk_char }, { CTL('B'), bk_char },
{ CTL('D'), del_char }, { CTL('D'), del_char },
{ CTL('E'), end_line }, { CTL('E'), end_line },
{ CTL('F'), fd_char }, { CTL('F'), fd_char },
{ CTL('G'), ring_bell }, { CTL('G'), el_ring_bell },
{ CTL('H'), bk_del_char }, { CTL('H'), bk_del_char },
{ CTL('I'), c_complete }, { CTL('I'), c_complete },
{ CTL('J'), accept_line }, { CTL('J'), accept_line },
@ -1559,13 +1559,13 @@ static el_keymap_t Map[33] = {
{ CTL('L'), redisplay }, { CTL('L'), redisplay },
{ CTL('M'), accept_line }, { CTL('M'), accept_line },
{ CTL('N'), h_next }, { CTL('N'), h_next },
{ CTL('O'), ring_bell }, { CTL('O'), el_ring_bell },
{ CTL('P'), h_prev }, { CTL('P'), h_prev },
{ CTL('Q'), ring_bell }, { CTL('Q'), el_ring_bell },
{ CTL('R'), h_search }, { CTL('R'), h_search },
{ CTL('S'), ring_bell }, { CTL('S'), el_ring_bell },
{ CTL('T'), transpose }, { CTL('T'), transpose },
{ CTL('U'), ring_bell }, { CTL('U'), el_ring_bell },
{ CTL('V'), quote }, { CTL('V'), quote },
{ CTL('W'), bk_kill_word }, { CTL('W'), bk_kill_word },
{ CTL('X'), exchange }, { CTL('X'), exchange },
@ -1573,12 +1573,12 @@ static el_keymap_t Map[33] = {
#ifdef SYSTEM_IS_WIN32 #ifdef SYSTEM_IS_WIN32
{ CTL('Z'), end_of_input }, { CTL('Z'), end_of_input },
#else #else
{ CTL('Z'), ring_bell }, { CTL('Z'), el_ring_bell },
#endif #endif
{ CTL('['), meta }, { CTL('['), meta },
{ CTL(']'), move_to_char }, { CTL(']'), move_to_char },
{ CTL('^'), ring_bell }, { CTL('^'), el_ring_bell },
{ CTL('_'), ring_bell }, { CTL('_'), el_ring_bell },
{ 0, NULL } { 0, NULL }
}; };
@ -1602,31 +1602,40 @@ static el_keymap_t MetaMap[64]= {
{ 0, NULL } { 0, NULL }
}; };
void el_bind_key_in_metamap(char c, el_keymap_func_t func) static void el_bind_key_in_map(int key, el_keymap_func_t function, el_keymap_t map[], size_t mapsz)
{ {
/* Add given function to key map for META keys */ size_t i;
int i;
for (i = 0; MetaMap[i].Key != 0; i++) for (i = 0; Map[i].Function != NULL; i++)
{ {
if (MetaMap[i].Key == c) if (map[i].Key == key)
{ {
MetaMap[i].Function = func; map[i].Function = function;
return; return;
} }
} }
/* A new key so have to add it to end */ /* A new key so have to add it to end */
if (i == 63) if (i == mapsz)
{ {
fprintf(stderr,"editline: MetaMap table full, requires increase\n"); fprintf(stderr,"editline: failed binding key 0x%x, keymap full.\n", key);
return; return;
} }
MetaMap[i].Function = func; map[i].Key = key;
MetaMap[i].Key = c; map[i].Function = function;
MetaMap[i + 1].Function = 0; /* Zero the last location */
MetaMap[i + 1].Key = 0; /* Zero the last location */ map[i + 1].Function = NULL; /* Terminate list */
}
void el_bind_key(int key, el_keymap_func_t function)
{
el_bind_key_in_map(key, function, Map, ARRAY_ELEMENTS(Map));
}
void el_bind_key_in_metamap(int key, el_keymap_func_t function)
{
el_bind_key_in_map(key, function, MetaMap, ARRAY_ELEMENTS(MetaMap));
} }
/** /**

View File

@ -56,6 +56,9 @@
#define MEM_INC 64 #define MEM_INC 64
#define SCREEN_INC 256 #define SCREEN_INC 256
/* http://stackoverflow.com/questions/1598773/is-there-a-standard-function-in-c-that-would-return-the-length-of-an-array/1598827#1598827 */
#define ARRAY_ELEMENTS(arr) ((sizeof(arr)/sizeof(0[arr])) / ((size_t)(!(sizeof(arr) % sizeof(0[arr])))))
/* /*
** Variables and routines internal to this package. ** Variables and routines internal to this package.
*/ */