Ilya Zakharevich on Sun, 19 Apr 1998 07:45:06 +0200 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Implementation of wise completion |
The following patch implements wise completion discussed earlier today (partially in private email) and implements electric ( [ and {. In the real PARI release electricity of parens after TAB and electricity of ( [ { should be configurable, since many people do not like electric keys ;-). Enjoy, Ilya P.S. I also fixed a buglet with prototypes. --- ./src/gp/gp_rl.c~ Sat Feb 7 11:12:04 1998 +++ ./src/gp/gp_rl.c Sun Apr 19 01:35:34 1998 @@ -32,6 +32,48 @@ static entree *current_ep = NULL; typedef char** (*CF)(char*, char * (*)()); /* completion function */ typedef char* (*GF)(char*,int); /* generator function */ +static int pari_rl_back; +extern Function *rl_last_func; + +/* Wrapper around rl_complete to allow insertion of () with a point in + between. */ +static int +pari_rl_complete(int count, int key) +{ + int ret; + + pari_rl_back = 0; + rl_begin_undo_group(); + if (rl_last_func == pari_rl_complete) + rl_last_func = rl_complete; /* Make repeated TABs different */ + ret = rl_complete(count,key); + if (pari_rl_back && (pari_rl_back <= rl_point)) + rl_point -= pari_rl_back; + rl_end_undo_group(); + return ret; +} + +static const char paropen[] = "([{"; +static const char parclose[] = ")]}"; + +/* To allow insertion of () with a point in between. */ +static int +pari_rl_matched_insert(int count, int key) +{ + int i = 0, ret; + + while (paropen[i] && paropen[i] != key) + i++; + if (!paropen[i]) + return rl_insert(count,key); + rl_begin_undo_group(); + rl_insert(count,key); + ret = rl_insert(count,parclose[i]); + rl_point -= count; + rl_end_undo_group(); + return ret; +} + /* Attempt to complete on the contents of TEXT. START and END show the * region of TEXT that contains the word to complete. We can use the * entire line in case we want to do some simple parsing. Return the @@ -40,18 +82,31 @@ typedef char* (*GF)(char*,int); /* gener static char ** get_matches(int end, char *text, char* f(char*,int)) { - char **matches = ((CF) completion_matches)(text, (char *(*)(ANYARG))f); - + char **matches; + + rl_completion_append_character = ' '; + current_ep = NULL; + matches = ((CF) completion_matches)(text, (char *(*)(ANYARG))f); if (matches && ! matches[1] /* only one match */ - && ! current_ep /* this is not a variable */ + && current_ep + /* this is not a variable */ + && (EpVALENCE(current_ep) != EpVAR) && end >= 0 /* from command_completion */ && rl_line_buffer[end] != '(' ) { int i=strlen(matches[0]); - matches[0] = (char*) gprealloc(matches[0], i+2, i); - strcat(matches[0],"("); + /* Check whether it is a constant masked as a function: */ + char *s = current_ep->help; + while (is_keyword_char(*s)) + s++; + if (*s != '=') { /* Is not a variable, after all! */ + matches[0] = (char*) gprealloc(matches[0], i+3, i); + strcat(matches[0],"()"); + pari_rl_back = 1; + if (rl_point == rl_end) + rl_completion_append_character = '\0'; /* Do not append space. */ + } } - current_ep = NULL; if (under_emacs) { @@ -131,7 +186,7 @@ command_generator (char *text, int stat ep = ep->next; else break; - if (EpVALENCE(ep)==EpVAR) current_ep = ep; + current_ep = ep; text = add_junk(ep->name,text,junk); ep=ep->next; return text; } @@ -255,24 +310,60 @@ pari_completion (char *text, int start, while (start && rl_line_buffer[start] != '(' && rl_line_buffer[start] != ',') start--; - if (rl_line_buffer[start] == '(') + if (rl_line_buffer[start] == '(' && start) { - beg = rl_line_buffer + start; - if (start >= 7) +#define MAX_KEYWORD 200 + int iend, j; + entree *ep; + char buf[MAX_KEYWORD]; + + i = start; + + while (i && isspace(rl_line_buffer[i - 1])) i--; + iend = i; + while (i && is_keyword_char(rl_line_buffer[i - 1])) i--; + + if (iend - i == 7) { - s = beg-7; - if (!strncmp(s,"default",7)) + if (strncmp(rl_line_buffer + i,"default",7) == 0) return get_matches(-1,text,default_generator); - if (!strncmp(s,"whatnow",7)) + if (strncmp(rl_line_buffer + i,"whatnow",7) == 0) return get_matches(-1,text,old_generator); - } + } - if (start>=4) + if (iend - i >= 4) { - s = beg-4; - if (!strncmp(s,"read",4)) + if (strncmp(rl_line_buffer + i,"read",4) == 0) return get_matches(-1,text,filename_completion_function); } + + j = start + 1; + while (j && isspace(rl_line_buffer[j])) j++; + /* If we are in empty parens, insert arguments for the function: */ + if ( (rl_line_buffer[j] == ')' || !rl_line_buffer[j] ) + && (iend - i < MAX_KEYWORD) + && ( strncpy(buf, rl_line_buffer + i, iend - i), + buf[iend - i] = 0, 1) + && (ep = is_entry(buf, functions_hash)) && ep->help) { + char *s = ep->help; + + while (is_keyword_char(*s)) + s++; + if (*s == '(') { /* Function, print arguments! */ + char *endh = ++s; + while (*endh && *endh != ')' && *endh != '(') + endh++; + if (*endh == ')') { /* Well-formed help. */ + char *str = strncpy((char*) gpmalloc(endh - s + 1), + s, endh - s); + char **ret = (char**)gpmalloc(sizeof(char*)*2); + str[endh - s] = 0; + ret[0] = str; + ret[1] = NULL; + return ret; + } + } + } } for(i=end-1;i>=start;i--) if (!is_keyword_char(rl_line_buffer[i])) @@ -332,15 +423,20 @@ init_readline(int i) Defun("short-help", (Function*) rl_short_help, -1); Defun("long-help", (Function*) rl_long_help, -1); + Defun("pari-complete", (Function*) pari_rl_complete, '\t'); + Defun("pari-matched-insert", (Function*) pari_rl_matched_insert, -1); Bind('h', (Function*) rl_short_help, emacs_meta_keymap); Bind('H', (Function*) rl_long_help, emacs_meta_keymap); Bind('h', (Function*) rl_short_help, vi_movement_keymap); Bind('H', (Function*) rl_long_help, vi_movement_keymap); + Bind('(', (Function*) pari_rl_matched_insert, emacs_standard_keymap); + Bind('[', (Function*) pari_rl_matched_insert, emacs_standard_keymap); + Bind('{', (Function*) pari_rl_matched_insert, emacs_standard_keymap); # ifdef EMACS_DOS_KEYMAP - Bind(';', (char*) rl_short_help, emacs_dos_keymap); /* F1 */ - Bind('T', (char*) rl_long_help, emacs_dos_keymap); /* Shift-F1 */ + Bind(';', (Function*) rl_short_help, emacs_dos_keymap); /* F1 */ + Bind('T', (Function*) rl_long_help, emacs_dos_keymap); /* Shift-F1 */ # endif } #endif