[BACK]Return to gp_rl.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / pari-2.2 / src / gp

Annotation of OpenXM_contrib/pari-2.2/src/gp/gp_rl.c, Revision 1.2

1.2     ! noro        1: /* $Id: gp_rl.c,v 1.18 2002/09/05 11:38:39 karim Exp $
1.1       noro        2:
                      3: Copyright (C) 2000  The PARI group.
                      4:
                      5: This file is part of the PARI/GP package.
                      6:
                      7: PARI/GP is free software; you can redistribute it and/or modify it under the
                      8: terms of the GNU General Public License as published by the Free Software
                      9: Foundation. It is distributed in the hope that it will be useful, but WITHOUT
                     10: ANY WARRANTY WHATSOEVER.
                     11:
                     12: Check the License for details. You should have received a copy of it, along
                     13: with the package; see the file 'COPYING'. If not, write to the Free Software
                     14: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
                     15:
                     16: /*******************************************************************/
                     17: /*                                                                 */
                     18: /*                 INTERFACE TO READLINE COMPLETION                */
                     19: /*                                                                 */
                     20: /*******************************************************************/
                     21: #include "pari.h"
                     22: #include "../language/anal.h"
                     23: #include "gp.h"
                     24:
                     25: #ifdef READLINE
1.2     ! noro       26: typedef char** (*CF)(char*, char* (*)(void)); /* completion function */
1.1       noro       27: typedef char* (*GF)(char*, int); /* generator function */
                     28: typedef int (*RLCI)(int, int); /* rl_complete and rl_insert functions */
                     29:
                     30: BEGINEXTERN
                     31: #ifdef HAS_RL_MESSAGE
                     32: #  define USE_VARARGS
                     33: #  define PREFER_STDARG
                     34: #endif
                     35: #ifdef READLINE_LIBRARY
                     36: #  include <readline.h>
1.2     ! noro       37: #  include <history.h>
1.1       noro       38: #else
                     39: #  include <readline/readline.h>
1.2     ! noro       40: #  include <readline/history.h>
1.1       noro       41: #endif
                     42: #ifndef HAS_RL_MESSAGE
                     43: extern int rl_message (const char *, ...);
                     44: extern int rl_clear_message();
                     45: extern int rl_begin_undo_group(), rl_end_undo_group();
                     46: extern int rl_read_key();
                     47: extern int rl_stuff_char();
                     48: extern char *filename_completion_function(char *text,int state);
                     49: extern char *username_completion_function(char *text,int state);
                     50: #endif
                     51: char **pari_completion(char *text, int start, int end);
                     52: ENDEXTERN
                     53:
                     54: void print_fun_list(char **matches, int nbli);
                     55: void aide(char *s, int flag);
                     56:
                     57: extern default_type gp_default_list[];
                     58: extern char *keyword_list[];
                     59: static int add_help_keywords;
                     60: static entree *current_ep = NULL;
                     61:
                     62: static int pari_rl_back;
                     63: extern RLCI rl_last_func;
                     64: static int do_args_complete = 1;
                     65: static int do_matched_insert = 0;
                     66: static int did_init_matched = 0;
                     67:
                     68: #ifdef HAS_RL_SAVE_PROMPT
                     69: #  define SAVE_PROMPT() rl_save_prompt()
                     70: #  define RESTORE_PROMPT() rl_restore_prompt()
                     71: #else
                     72: #  ifdef HAS_UNDERSCORE_RL_SAVE_PROMPT
                     73: #    define SAVE_PROMPT() _rl_save_prompt()
                     74: #    define RESTORE_PROMPT() _rl_restore_prompt()
                     75: #  else
                     76: #    define SAVE_PROMPT()
                     77: #    define RESTORE_PROMPT()
                     78: #  endif
                     79: #endif
                     80:
                     81: #ifdef HAS_RL_COMPLETION_MATCHES
                     82: #  define COMPLETION_MATCHES ((CF)rl_completion_matches)
                     83: #  define FILE_COMPLETION ((GF)rl_filename_completion_function)
                     84: #  define USER_COMPLETION ((GF)rl_username_completion_function)
                     85: #else
                     86: #  define COMPLETION_MATCHES ((CF)completion_matches)
                     87: #  define FILE_COMPLETION ((GF)filename_completion_function)
                     88: #  define USER_COMPLETION ((GF)username_completion_function)
                     89: #endif
                     90:
                     91: #define ELECTRIC_PAREN 1
                     92: #define ARGS_COMPLETE  2
                     93: static int
                     94: change_state(char *msg, int *opt, int count)
                     95: {
                     96:   int c;
                     97:
                     98:   switch(count)
                     99:   {
                    100:     default: c = 0; break; /* off */
                    101:     case -1: c = 1; break; /* on  */
                    102:     case -2: c = 1 - *opt; /* toggle */
                    103:   }
                    104:   *opt = c;
                    105:   SAVE_PROMPT();
1.2     ! noro      106:   rl_message("%s: %s.", msg, c? "on": "off");
1.1       noro      107:   c = rl_read_key();
                    108:   RESTORE_PROMPT();
                    109:   rl_clear_message();
                    110:   rl_stuff_char(c); return 1;
                    111: }
                    112:
                    113: /* Wrapper around rl_complete to allow toggling insertion of arguments */
                    114: static int
                    115: pari_rl_complete(int count, int key)
                    116: {
                    117:   int ret;
                    118:
                    119:   pari_rl_back = 0;
                    120:   if (count <= 0)
                    121:     return change_state("complete args", &do_args_complete, count);
                    122:
                    123:   rl_begin_undo_group();
                    124:   if (rl_last_func == pari_rl_complete)
                    125:     rl_last_func = (RLCI) rl_complete; /* Make repeated TABs different */
                    126:   ret = ((RLCI)rl_complete)(count,key);
                    127:   if (pari_rl_back && (pari_rl_back <= rl_point))
                    128:     rl_point -= pari_rl_back;
                    129:   rl_end_undo_group(); return ret;
                    130: }
                    131:
                    132: static const char paropen[] = "([{";
                    133: static const char parclose[] = ")]}";
                    134:
                    135: /* To allow insertion of () with a point in between. */
                    136: static int
                    137: pari_rl_matched_insert(int count, int key)
                    138: {
                    139:   int i = 0, ret;
                    140:
                    141:   if (count <= 0)
                    142:     return change_state("electric parens", &do_matched_insert, count);
                    143:   while (paropen[i] && paropen[i] != key) i++;
1.2     ! noro      144:   if (!paropen[i] || !do_matched_insert || GP_DATA->flags & EMACS)
1.1       noro      145:     return ((RLCI)rl_insert)(count,key);
                    146:   rl_begin_undo_group();
                    147:   ((RLCI)rl_insert)(count,key);
                    148:   ret = ((RLCI)rl_insert)(count,parclose[i]);
                    149:   rl_point -= count;
                    150:   rl_end_undo_group(); return ret;
                    151: }
                    152:
                    153: static int
                    154: pari_rl_default_matched_insert(int count, int key)
                    155: {
                    156:     if (!did_init_matched) {
                    157:        did_init_matched = 1;
                    158:        do_matched_insert = 1;
                    159:     }
                    160:     return pari_rl_matched_insert(count, key);
                    161: }
                    162:
                    163: static int
                    164: pari_rl_forward_sexp(int count, int key)
                    165: {
                    166:   int deep = 0, dir = 1, move_point = 0, lfail;
                    167:
                    168:   (void)key;
                    169:   if (count < 0)
                    170:   {
                    171:     count = -count; dir = -1;
                    172:     if (!rl_point) goto fail;
                    173:     rl_point--;
                    174:   }
                    175:   while (count || deep)
                    176:   {
                    177:     move_point = 1;    /* Need to move point if moving left. */
                    178:     lfail = 0;         /* Do not need to fail left movement yet. */
                    179:     while ( !is_keyword_char(rl_line_buffer[rl_point])
                    180:             && !strchr("\"([{}])",rl_line_buffer[rl_point])
                    181:             && !( (dir == 1)
                    182:                   ? (rl_point >= rl_end)
                    183:                   : (rl_point <= 0 && (lfail = 1))))
                    184:         rl_point += dir;
                    185:     if (lfail || !rl_line_buffer[rl_point]) goto fail;
                    186:
                    187:     if (is_keyword_char(rl_line_buffer[rl_point]))
                    188:     {
                    189:       while ( is_keyword_char(rl_line_buffer[rl_point])
                    190:               && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
                    191:                   || (move_point = 0)))
                    192:         rl_point += dir;
                    193:       if (!deep) count--;
                    194:     }
                    195:     else if (strchr(paropen,rl_line_buffer[rl_point]))
                    196:     {
                    197:       if (deep == 0 && dir == -1) goto fail; /* We are already out of pars. */
                    198:       rl_point += dir;
                    199:       deep++; if (!deep) count--;
                    200:     }
                    201:     else if (strchr(parclose,rl_line_buffer[rl_point]))
                    202:     {
                    203:       if (deep == 0 && dir == 1)
                    204:       {
                    205:         rl_point++; goto fail; /* Get out of pars. */
                    206:       }
                    207:       rl_point += dir;
                    208:       deep--; if (!deep) count--;
                    209:     }
                    210:     else if (rl_line_buffer[rl_point] == '\"')
                    211:     {
                    212:       int bad = 1;
                    213:
                    214:       rl_point += dir;
                    215:       while ( ((rl_line_buffer[rl_point] != '\"') || (bad = 0))
                    216:               && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
                    217:                   || (move_point = 0)) )
                    218:         rl_point += dir;
                    219:       if (bad) goto fail;
                    220:       rl_point += dir; /* Skip the other delimiter */
                    221:       if (!deep) count--;
                    222:     }
                    223:     else
                    224:     {
                    225:       fail: ding(); return 1;
                    226:     }
                    227:   }
                    228:   if (dir != 1 && move_point) rl_point++;
                    229:   return 1;
                    230: }
                    231:
                    232: static int
                    233: pari_rl_backward_sexp(int count, int key)
                    234: {
                    235:   return pari_rl_forward_sexp(-count, key);
                    236: }
                    237:
                    238: /* do we add () at the end of completed word? (is it a function?) */
                    239: static int
                    240: add_paren(int end)
                    241: {
                    242:   entree *ep;
                    243:   char *s;
                    244:
                    245:   if (end < 0 || rl_line_buffer[end] == '(')
                    246:     return 0; /* not from command_generator or already there */
                    247:   ep = do_alias(current_ep); /* current_ep set in command_generator */
                    248:   if (EpVALENCE(ep) < EpUSER)
                    249:   { /* is it a constant masked as a function (e.g Pi)? */
                    250:     s = ep->help; if (!s) return 1;
                    251:     while (is_keyword_char(*s)) s++;
                    252:     return (*s != '=');
                    253:   }
                    254:   switch(EpVALENCE(ep))
                    255:   {
                    256:     case EpUSER:
                    257:     case EpINSTALL: return 1;
                    258:   }
                    259:   return 0;
                    260: }
                    261:
                    262: static void
                    263: match_concat(char **matches, char *s)
                    264: {
1.2     ! noro      265:   matches[0] = (char*) gprealloc(matches[0], strlen(matches[0])+strlen(s)+1);
1.1       noro      266:   strcat(matches[0],s);
                    267: }
                    268:
                    269: static char **
                    270: matches_for_emacs(char *text, char **matches)
                    271: {
                    272:   if (!matches) printf("@");
                    273:   else
                    274:   {
                    275:     int i;
                    276:     printf("%s@", matches[0] + strlen(text));
                    277:     if (matches[1]) print_fun_list(matches+1,0);
                    278:
                    279:    /* we don't want readline to do anything, but insert some junk
                    280:     * which will be erased by emacs.
                    281:     */
                    282:     for (i=0; matches[i]; i++) free(matches[i]);
                    283:     free(matches);
                    284:   }
                    285:   matches = (char **) gpmalloc(2*sizeof(char *));
                    286:   matches[0] = gpmalloc(2); sprintf(matches[0],"_");
                    287:   matches[1] = NULL; printf("@E_N_D"); pariflush();
                    288:   return matches;
                    289: }
                    290:
                    291: #define add_comma(x) (x==-2) /* from default_generator */
                    292:
                    293: /* Attempt to complete on the contents of TEXT. END points to the end of the
                    294:  * word to complete. Return the array of matches, or NULL if there aren't any.
                    295:  */
                    296: static char **
                    297: get_matches(int end, char *text, char* f(char*,int))
                    298: {
                    299:   char **matches;
                    300:
                    301: #ifdef HAS_COMPLETION_APPEND_CHAR
                    302:   rl_completion_append_character = ' ';
                    303: #endif
                    304:   current_ep = NULL;
1.2     ! noro      305:   matches = COMPLETION_MATCHES(text, (char *(*)(void))f);
1.1       noro      306:   if (matches && !matches[1]) /* a single match */
                    307:   {
                    308:     if (add_paren(end))
                    309:     {
                    310:       match_concat(matches,"()");
                    311:       pari_rl_back = 1;
                    312:       if (rl_point == rl_end)
                    313: #ifdef HAS_COMPLETION_APPEND_CHAR
                    314:         rl_completion_append_character = '\0'; /* Do not append space. */
                    315: #else
                    316:         pari_rl_back = 2;
                    317: #endif
                    318:     }
                    319:     else if (add_comma(end))
                    320:       match_concat(matches,",");
                    321:   }
1.2     ! noro      322:   if (GP_DATA->flags & EMACS) matches = matches_for_emacs(text,matches);
1.1       noro      323:   return matches;
                    324: }
                    325: #undef add_comma
                    326:
                    327: static char *
                    328: add_junk(char *name, char *text, long junk)
                    329: {
                    330:   char *s = strncpy((char*) gpmalloc(strlen(name)+1+junk),text,junk);
                    331:   strcpy(s+junk,name); return s;
                    332: }
                    333:
                    334: /* Generator function for command completion.  STATE lets us know whether
                    335:  * to start from scratch; without any state (i.e. STATE == 0), then we
                    336:  * start at the top of the list.
                    337:  */
                    338: static char *
                    339: hashtable_generator (char *text, int state, entree **hash)
                    340: {
                    341:   static int hashpos, len, junk, n;
                    342:   static entree* ep;
                    343:   static char *TEXT;
                    344:
                    345:  /* If this is a new word to complete, initialize now:
                    346:   *  + indexes hashpos (GP hash list) and n (keywords specific to long help).
                    347:   *  + file completion and keyword completion use different word boundaries,
                    348:   *    have TEXT point to the keyword start.
                    349:   *  + save the length of TEXT for efficiency.
                    350:   */
                    351:   if (!state)
                    352:   {
                    353:     n = hashpos = 0; ep=hash[hashpos];
                    354:     len=strlen(text); junk=len-1;
                    355:     while (junk >= 0 && is_keyword_char(text[junk])) junk--;
                    356:     junk++; len -= junk; TEXT = text + junk;
                    357:   }
                    358:
                    359:   /* First check the keywords list */
                    360:   if (add_help_keywords)
                    361:   {
                    362:     for ( ; keyword_list[n]; n++)
                    363:       if (!strncmp(keyword_list[n],TEXT,len))
                    364:       {
                    365:         text = add_junk(keyword_list[n],text,junk);
                    366:         n++; return text;
                    367:       }
                    368:   }
                    369:
                    370:   /* Return the next name which partially matches from the command list. */
                    371:   for(;;)
                    372:     if (!ep)
                    373:     {
                    374:       if (++hashpos >= functions_tblsz) return NULL; /* no names matched */
                    375:       ep = hash[hashpos];
                    376:     }
                    377:     else if (strncmp(ep->name,TEXT,len))
                    378:       ep = ep->next;
                    379:     else
                    380:       break;
                    381:   current_ep = ep;
                    382:   text = add_junk(ep->name,text,junk);
                    383:   ep=ep->next; return text;
                    384: }
                    385:
                    386: static char *
                    387: command_generator (char *text, int  state)
                    388: {
                    389:   return hashtable_generator(text,state, functions_hash);
                    390: }
                    391: static char *
                    392: member_generator (char *text, int  state)
                    393: {
                    394:   return hashtable_generator(text,state, members_hash);
                    395: }
                    396:
                    397: #define DFLT 0
                    398: #define ENTREE 1
                    399:
                    400: static char *
                    401: generator(void *list, char *text, int *nn, int len, int typ)
                    402: {
                    403:   char *def = NULL, *name;
                    404:   int n = *nn;
                    405:
                    406:   /* Return the next name which partially matches from list.*/
                    407:   switch(typ)
                    408:   {
                    409:     case DFLT :
                    410:       do
                    411:        def = (((default_type *) list)[n++]).name;
                    412:       while (def && strncmp(def,text,len));
                    413:       break;
                    414:
                    415:     case ENTREE :
                    416:       do
                    417:        def = (((entree *) list)[n++]).name;
                    418:       while (def && strncmp(def,text,len));
                    419:   }
                    420:
                    421:   *nn = n;
                    422:   if (def)
                    423:   {
                    424:     name = strcpy((char*) gpmalloc(strlen(def)+1), def);
                    425:     return name;
                    426:   }
                    427:   return NULL; /* no names matched */
                    428: }
                    429:
                    430: static char *
                    431: old_generator(char *text,int state)
                    432: {
                    433:   static int n,len;
                    434:   static char *res;
                    435:
                    436:   if (!state) { res = "a"; n=0; len=strlen(text); }
                    437:   if (res)
                    438:   {
                    439:     res = generator((void *)oldfonctions,text,&n,len,ENTREE);
                    440:     if (res) return res;
                    441:     n=0;
                    442:   }
                    443:   return generator((void *)functions_oldgp,text,&n,len,ENTREE);
                    444: }
                    445:
                    446: static char *
                    447: default_generator(char *text,int state)
                    448: {
                    449:   static int n,len;
                    450:
                    451:   if (!state) { n=0; len=strlen(text); }
                    452:   return generator(gp_default_list,text,&n,len,DFLT);
                    453: }
                    454:
                    455: static void
                    456: rl_print_aide(char *s, int flag)
                    457: {
                    458:   int p = rl_point, e = rl_end;
                    459:   FILE *save = pari_outfile;
                    460:
                    461:   rl_point = 0; rl_end = 0; pari_outfile = rl_outstream;
                    462:   SAVE_PROMPT();
1.2     ! noro      463:   rl_message("%s",""); /* rl_message("") ==> "zero length format" warning */
1.1       noro      464:   aide(s, flag);
                    465:   RESTORE_PROMPT();
                    466:   rl_point = p; rl_end = e; pari_outfile = save;
                    467:   rl_clear_message();
                    468: #ifdef RL_REFRESH_LINE_OLDPROTO
                    469:   rl_refresh_line();
                    470: #else
                    471:   rl_refresh_line(0,0);
                    472: #endif
                    473: }
                    474:
                    475: char **
                    476: pari_completion(char *text, int START, int END)
                    477: {
                    478:   int i, first=0, start=START;
                    479:
                    480: /* If the line does not begin by a backslash, then it is:
                    481:  * . an old command ( if preceded by "whatnow(" ).
                    482:  * . a default ( if preceded by "default(" ).
                    483:  * . a member function ( if preceded by "." within 4 letters )
                    484:  * . a file name (in current directory) ( if preceded by "read(" )
                    485:  * . a command
                    486:  */
                    487:   if (start >=1 && rl_line_buffer[start] != '~') start--;
                    488:   while (start && is_keyword_char(rl_line_buffer[start])) start--;
                    489:   if (rl_line_buffer[start] == '~')
                    490:   {
                    491:     for(i=start+1;i<=END;i++)
                    492:       if (rl_line_buffer[i] == '/')
                    493:        return get_matches(-1,text,FILE_COMPLETION);
                    494:     return get_matches(-1,text,USER_COMPLETION);
                    495:   }
                    496:
                    497:   while (rl_line_buffer[first] && isspace((int)rl_line_buffer[first])) first++;
                    498:   switch (rl_line_buffer[first])
                    499:   {
                    500:     case '\\':
                    501:       if (first == start) text = rl_line_buffer+start+2;
                    502:       return get_matches(-1,text,FILE_COMPLETION);
                    503:     case '?':
                    504:       if (rl_line_buffer[first+1] == '?') add_help_keywords = 1;
                    505:       return get_matches(-1,text,command_generator);
                    506:   }
                    507:
                    508:   while (start && rl_line_buffer[start] != '('
                    509:                && rl_line_buffer[start] != ',') start--;
                    510:   if (rl_line_buffer[start] == '(' && start)
                    511:   {
                    512: #define MAX_KEYWORD 200
                    513:     int iend, j,k;
                    514:     entree *ep;
                    515:     char buf[MAX_KEYWORD];
                    516:
                    517:     i = start;
                    518:
                    519:     while (i && isspace((int)rl_line_buffer[i-1])) i--;
                    520:     iend = i;
                    521:     while (i && is_keyword_char(rl_line_buffer[i-1])) i--;
                    522:
                    523:     if (iend - i == 7)
                    524:     {
                    525:       if (strncmp(rl_line_buffer + i,"default",7) == 0)
                    526:        return get_matches(-2,text,default_generator);
                    527:       if (strncmp(rl_line_buffer + i,"whatnow",7) == 0)
                    528:        return get_matches(-1,text,old_generator);
                    529:     }
                    530:     if (iend - i >= 4)
                    531:     {
                    532:       if (strncmp(rl_line_buffer + i,"read",4) == 0)
                    533:        return get_matches(-1,text,FILE_COMPLETION);
                    534:     }
                    535:
                    536:     j = start + 1;
                    537:     while (j <= END && isspace((int)rl_line_buffer[j])) j++;
                    538:     k = END;
                    539:     while (k > j && isspace((int)rl_line_buffer[k])) k--;
1.2     ! noro      540:     /* If we are in empty parens, output function help */
1.1       noro      541:     if (do_args_complete && k == j
                    542:          && (rl_line_buffer[j] == ')' || !rl_line_buffer[j])
                    543:         && (iend - i < MAX_KEYWORD)
                    544:         && ( strncpy(buf, rl_line_buffer + i, iend - i),
                    545:              buf[iend - i] = 0, 1)
                    546:         && (ep = is_entry(buf)) && ep->help)
                    547:      {
                    548:       rl_print_aide(buf,h_RL);
                    549:       rl_attempted_completion_over = 1;
                    550:       return NULL;
                    551:     }
                    552:   }
                    553:   for(i=END-1;i>=start;i--)
                    554:     if (!is_keyword_char(rl_line_buffer[i]))
                    555:     {
                    556:       if (rl_line_buffer[i] == '.')
                    557:         return get_matches(-1,text,member_generator);
                    558:       break;
                    559:     }
                    560:   add_help_keywords = 0;
                    561:   return get_matches(END,text,command_generator);
                    562: }
                    563:
                    564: /* long help if count < 0 */
                    565: static int
                    566: rl_short_help(int count, int key)
                    567: {
                    568:   int flag = (count < 0 || rl_last_func == rl_short_help)? h_RL|h_LONG: h_RL;
                    569:   int off = rl_point;
                    570:
                    571:   /* func() with cursor on ')' following completion */
                    572:   if (off && rl_line_buffer[off-1] == '('
                    573:           && !is_keyword_char(rl_line_buffer[off])) off--;
                    574:
                    575:   while (off && is_keyword_char(rl_line_buffer[off-1])) off--;
                    576:
                    577:   /* Check for \c type situation.  Could check for leading whitespace too... */
                    578:   if (off == 1 && rl_line_buffer[off-1] == '\\') off--;
                    579:   if (off >= 8) {              /* Check for default(whatever) */
                    580:     int t = off - 1;
                    581:
                    582:     while (t >= 7 && isspace((int)rl_line_buffer[t])) t--;
                    583:     if (rl_line_buffer[t--] == '(') {
                    584:       while (t >= 6 && isspace((int)rl_line_buffer[t])) t--;
                    585:       t -= 6;
                    586:       if (t >= 0
                    587:          && strncmp(rl_line_buffer + t, "default", 7) == 0
                    588:          && (t == 0 || !is_keyword_char(rl_line_buffer[t-1])))
                    589:        off = t;
                    590:     }
                    591:   }
                    592:   rl_print_aide(rl_line_buffer + off, flag);
                    593:   return 0;
                    594: }
                    595:
                    596: static int
                    597: rl_long_help(int count, int key)
                    598: {
                    599:   (void)count;
                    600:   return rl_short_help(-1,key);
                    601: }
                    602:
                    603: void
1.2     ! noro      604: init_readline(void)
1.1       noro      605: {
                    606:   /* Allow conditional parsing of the ~/.inputrc file. */
                    607:   rl_readline_name = "Pari-GP";
                    608:
                    609:   /* added ~, ? and , */
                    610:   rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(?,~";
                    611:   rl_special_prefixes = "~";
                    612:
                    613:   /* custom completer */
                    614: #ifndef HAS_RL_COMPLETION_FUNC_T
                    615: # ifndef CPPFunction_defined
                    616: #   define CPPFunction Function
                    617: # endif
                    618: # define rl_completion_func_t CPPFunction
                    619: #endif
                    620:   rl_attempted_completion_function = (rl_completion_func_t*) pari_completion;
                    621:
                    622:   /* we always want the whole list of completions under emacs */
1.2     ! noro      623:   if (GP_DATA->flags & EMACS) rl_completion_query_items = 0x8fff;
1.1       noro      624:
                    625: #define Bind(a,b,c) (((void(*)(int,Function*,Keymap)) rl_bind_key_in_map)\
                    626:   ((a), (Function*)(b), (c)))
                    627: #define Defun(a,b,c) (((void(*)(const char*,Function*,int)) rl_add_defun)\
                    628:   ((a), (Function*)(b), (c)))
                    629:
                    630:   Defun("short-help", rl_short_help, -1);
                    631:   Defun("long-help", rl_long_help, -1);
                    632:   Defun("pari-complete", pari_rl_complete, '\t');
                    633:   Defun("pari-matched-insert", pari_rl_default_matched_insert, -1);
                    634:   Defun("pari-forward-sexp", pari_rl_forward_sexp, -1);
                    635:   Defun("pari-backward-sexp", pari_rl_backward_sexp, -1);
                    636:
                    637:   Bind('h', rl_short_help, emacs_meta_keymap);
                    638:   Bind('H', rl_long_help,  emacs_meta_keymap);
                    639:   Bind('h', rl_short_help, vi_movement_keymap);
                    640:   Bind('H', rl_long_help,  vi_movement_keymap);
                    641: #  ifdef HAS_RL_GENERIC_BIND
                    642: #define KSbind(s,f,k) rl_generic_bind(ISFUNC, (s), (char*)(f), (k))
                    643:
                    644:   KSbind("OP",   rl_short_help,  emacs_meta_keymap); /* f1, vt100 */
                    645:   KSbind("[11~", rl_short_help,  emacs_meta_keymap); /* f1, xterm */
                    646:   KSbind("OP",   rl_short_help,  vi_movement_keymap); /* f1, vt100 */
                    647:   KSbind("[11~", rl_short_help,  vi_movement_keymap); /* f1, xterm */
                    648: #  endif
                    649:   Bind('(', pari_rl_matched_insert, emacs_standard_keymap);
                    650:   Bind('[', pari_rl_matched_insert, emacs_standard_keymap);
                    651:   Bind(6, pari_rl_forward_sexp,  emacs_meta_keymap); /* M-C-f */
                    652:   Bind(2, pari_rl_backward_sexp, emacs_meta_keymap); /* M-C-b */
                    653:
                    654: #ifdef EMACS_DOS_KEYMAP
                    655:   Bind(';', rl_short_help, emacs_dos_keymap); /* F1 */
                    656:   Bind('T', rl_long_help,  emacs_dos_keymap); /* Shift-F1 */
                    657:   Bind(155, pari_rl_backward_sexp, emacs_dos_keymap); /* Alt-Left */
                    658:   Bind(157, pari_rl_forward_sexp,  emacs_dos_keymap); /* Alt-Right*/
                    659: #endif
1.2     ! noro      660: }
        !           661:
        !           662: static int
        !           663: history_is_new(char *s)
        !           664: {
        !           665:   return (*s && (!history_length ||
        !           666:                   strcmp(s, history_get(history_length)->line)));
        !           667: }
        !           668:
        !           669: static void
        !           670: gp_add_history(char *s)
        !           671: {
        !           672:   if (history_is_new(s)) add_history(s);
        !           673: }
        !           674:
        !           675: extern void fix_buffer(Buffer *b, long newlbuf);
        !           676: extern int input_loop(filtre_t *F, input_method *IM);
        !           677:
        !           678: /* Read line; returns a malloc()ed string of the user input or NULL on EOF.
        !           679:    Increments the buffer size appropriately if needed; fix *endp if so. */
        !           680: static char *
        !           681: gprl_input(Buffer *b, char **endp, input_method *IM)
        !           682: {
        !           683:   long used = *endp - b->buf;
        !           684:   long left = b->len - used, l;
        !           685:   char *s;
        !           686:
        !           687:   if (! (s = readline(IM->prompt)) ) return NULL; /* EOF */
        !           688:   l = strlen(s);
        !           689:   if ((ulong)left < l)
        !           690:   {
        !           691:     long incr = b->len;
        !           692:
        !           693:     if (incr < l) incr = l;
        !           694:     fix_buffer(b, b->len + incr);
        !           695:     *endp = b->buf + used;
        !           696:   }
        !           697:   gp_add_history(s); /* Makes a copy */
        !           698:   return s;
        !           699: }
        !           700:
        !           701: static void
        !           702: unblock_SIGINT(void)
        !           703: {
        !           704: #ifdef USE_SIGRELSE
        !           705:   sigrelse(SIGINT);
        !           706: #elif USE_SIGSETMASK
        !           707:   sigsetmask(0);
        !           708: #endif
        !           709: }
        !           710:
        !           711: /* request one line interactively.
        !           712:  * Return 0: EOF
        !           713:  *        1: got one line from readline or infile */
        !           714: int
        !           715: get_line_from_readline(char *prompt, filtre_t *F)
        !           716: {
        !           717:   const int index = history_length;
        !           718:   char *s;
        !           719:   input_method IM;
        !           720:
        !           721:   IM.prompt = prompt;
        !           722:   IM.getline= &gprl_input;
        !           723:   IM.free = 1;
        !           724:   if (! input_loop(F,&IM)) { pariputs("\n"); return 0; }
        !           725:
        !           726:   s = ((Buffer*)F->data)->buf;
        !           727:   if (*s)
        !           728:   {
        !           729:     if (history_length > index+1)
        !           730:     { /* Multi-line input. Remove incomplete lines */
        !           731:       int i = history_length;
        !           732:       while (i > index) {
        !           733:         HIST_ENTRY *e = remove_history(--i);
        !           734:         free(e->line); free(e);
        !           735:       }
        !           736:       gp_add_history(s);
        !           737:     }
        !           738:
        !           739:     /* update logfile */
        !           740:     if (logfile) fprintf(logfile, "%s%s\n",prompt,s);
        !           741:   }
        !           742:   unblock_SIGINT(); /* bug in readline 2.0: need to unblock ^C */
        !           743:   return 1;
1.1       noro      744: }
                    745: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>