| 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