Ilya Zakharevich on Thu, 17 Oct 2002 12:08:40 -0700


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[PATCH CVS] Readline improvements


[Some time ago F1/M-h did not work before parentheses of 

  function()

Apparently, it was recently fixed.  However, in between somebody
noticed this lack of functionallity, and switched off an important
feature of TAB - to make TAB work as F1 in this situation.  Thus
currently F1 and TAB do the same between parentheses (as above).]

This patch:

  a) Restores the historic behaviour of TAB (insert the template for
     function arguments), if one wants help, press F1 or M-h;

  b) make default(readline,4) and default(readline,2) etc. switch the
     electric TAB (as above) and electric-parens settings;

  c) Better formatting of the message when one switches the two
     setting above (by giving non-positive arguments to TAB or "(");

  d) Colors now work with default(readline,0) too;

  e) Beginning of support for Mouse-Editing in xterm (see
http://groups.google.com/groups?selm=ani7hg%24bmf%241%40agate.berkeley.edu&output=gplain).

     Currently we support the 2004 setting by interpreting F200/F201
     as signals to switch off/back electric parens.  In particular,
     one can have default(readline,2) *and* cut-and-paste in new xterm
     without bad interactions (if one enables 2004 before entering gp).

     This probably is not 100%-proof in vi-mode.  However, I cannot
     fix it, since I'm vi-ignorant.

Enjoy,
Ilya

--- ./src/gp/gp_rl.c-pre3	Tue Oct 15 20:26:50 2002
+++ ./src/gp/gp_rl.c	Thu Oct 17 03:08:46 2002
@@ -61,8 +61,6 @@ static entree *current_ep = NULL;
 
 static int pari_rl_back;
 extern RLCI rl_last_func;
-static int do_args_complete = 1;
-static int do_matched_insert = 0;
 static int did_init_matched = 0;
 
 #ifdef HAS_RL_SAVE_PROMPT
@@ -88,22 +86,32 @@ static int did_init_matched = 0;
 #  define USER_COMPLETION ((GF)username_completion_function)
 #endif
 
-#define ELECTRIC_PAREN 1
-#define ARGS_COMPLETE  2
 static int
-change_state(char *msg, int *opt, int count)
+change_state(char *msg, ulong flag, int count)
 {
-  int c;
+  int c = (readline_state & flag) != 0;
+  ulong o_readline_state = readline_state;
 
   switch(count)
   {
     default: c = 0; break; /* off */
     case -1: c = 1; break; /* on  */
-    case -2: c = 1 - *opt; /* toggle */
+    case -2: c = 1 - c; /* toggle */
+  }
+  if (c)
+    readline_state |= flag;
+  else {
+    readline_state &= ~flag;
+    if (!readline_state && o_readline_state)
+	readline_state = 1;
   }
-  *opt = c;
   SAVE_PROMPT();
-  rl_message("%s: %s.", msg, c? "on": "off");
+#if 0				/* Does not work well... */
+  rl_message("%s[%s: %s] %s", term_get_color(c_PROMPT),
+	     msg, c? "on": "off", term_get_color(c_INPUT));
+#else
+  rl_message("[%s: %s] ", msg, c? "on": "off");
+#endif
   c = rl_read_key();
   RESTORE_PROMPT();
   rl_clear_message();
@@ -118,7 +126,7 @@ pari_rl_complete(int count, int key)
 
   pari_rl_back = 0;
   if (count <= 0)
-    return change_state("complete args", &do_args_complete, count);
+    return change_state("complete args", DO_ARGS_COMPLETE, count);
 
   rl_begin_undo_group();
   if (rl_last_func == pari_rl_complete)
@@ -129,6 +137,28 @@ pari_rl_complete(int count, int key)
   rl_end_undo_group(); return ret;
 }
 
+static int did_matched_insert;
+
+static int
+pari_rl_matched_insert_suspend(int count, int key)
+{
+  ulong o_readline_state = readline_state;
+
+  did_matched_insert = (readline_state & DO_MATCHED_INSERT);
+  readline_state &= ~DO_MATCHED_INSERT;
+  if (!readline_state && o_readline_state)
+    readline_state = 1;
+  return 1;
+}
+
+static int
+pari_rl_matched_insert_restore(int count, int key)
+{
+  if (did_matched_insert)
+    readline_state |= DO_MATCHED_INSERT;
+  return 1;
+}
+
 static const char paropen[] = "([{";
 static const char parclose[] = ")]}";
 
@@ -139,9 +169,9 @@ pari_rl_matched_insert(int count, int ke
   int i = 0, ret;
 
   if (count <= 0)
-    return change_state("electric parens", &do_matched_insert, count);
+    return change_state("electric parens", DO_MATCHED_INSERT, count);
   while (paropen[i] && paropen[i] != key) i++;
-  if (!paropen[i] || !do_matched_insert || GP_DATA->flags & EMACS)
+  if (!paropen[i] || !(readline_state & DO_MATCHED_INSERT) || GP_DATA->flags & EMACS)
     return ((RLCI)rl_insert)(count,key);
   rl_begin_undo_group();
   ((RLCI)rl_insert)(count,key);
@@ -155,7 +185,7 @@ pari_rl_default_matched_insert(int count
 {
     if (!did_init_matched) {
 	did_init_matched = 1;
-	do_matched_insert = 1;
+	readline_state |= DO_MATCHED_INSERT;
     }
     return pari_rl_matched_insert(count, key);
 }
@@ -537,17 +567,37 @@ pari_completion(char *text, int START, i
     while (j <= END && isspace((int)rl_line_buffer[j])) j++;
     k = END;
     while (k > j && isspace((int)rl_line_buffer[k])) k--;
-    /* If we are in empty parens, output function help */
-    if (do_args_complete && k == j
+    /* If we are in empty parens, insert the default arguments */
+    if ((readline_state & DO_ARGS_COMPLETE) && k == j
          && (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)) && ep->help)
      {
+#if 1
+      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;
+          if (GP_DATA->flags & EMACS) ret = matches_for_emacs("",ret);
+          return ret;
+        }
+      }
+#else			/* Why duplicate F1 (and emit a bell)?! */
       rl_print_aide(buf,h_RL);
       rl_attempted_completion_over = 1;
       return NULL;
+#endif
     }
   }
   for(i=END-1;i>=start;i--)
@@ -631,6 +681,8 @@ init_readline(void)
   Defun("long-help", rl_long_help, -1);
   Defun("pari-complete", pari_rl_complete, '\t');
   Defun("pari-matched-insert", pari_rl_default_matched_insert, -1);
+  Defun("pari-matched-insert-suspend", pari_rl_matched_insert_suspend, -1);
+  Defun("pari-matched-insert-restore", pari_rl_matched_insert_restore, -1);
   Defun("pari-forward-sexp", pari_rl_forward_sexp, -1);
   Defun("pari-backward-sexp", pari_rl_backward_sexp, -1);
 
@@ -645,6 +697,13 @@ init_readline(void)
   KSbind("[11~", rl_short_help,  emacs_meta_keymap); /* f1, xterm */
   KSbind("OP",   rl_short_help,  vi_movement_keymap); /* f1, vt100 */
   KSbind("[11~", rl_short_help,  vi_movement_keymap); /* f1, xterm */
+  /* XTerm may signal start/end of paste by eming F200/F201 */
+  /* XXXX For vi mode something more intelligent is needed - to switch to the
+     insert mode - and back when restoring. */
+  KSbind("[200~", pari_rl_matched_insert_suspend,  emacs_meta_keymap);  /* pre-paste xterm */
+  KSbind("[200~", pari_rl_matched_insert_suspend,  vi_movement_keymap); /* pre-paste xterm */
+  KSbind("[201~", pari_rl_matched_insert_restore,  emacs_meta_keymap);  /* post-paste xterm */
+  KSbind("[201~", pari_rl_matched_insert_restore,  vi_movement_keymap); /* post-paste xterm */
 #  endif
   Bind('(', pari_rl_matched_insert, emacs_standard_keymap);
   Bind('[', pari_rl_matched_insert, emacs_standard_keymap);
--- ./src/gp/gp.c-pre3	Tue Oct 15 20:26:00 2002
+++ ./src/gp/gp.c	Thu Oct 17 02:51:42 2002
@@ -637,16 +637,31 @@ static GEN
 sd_debug(char *v, int flag)
 { return sd_ulong(v,flag,"debug",&DEBUGLEVEL, 0,20,NULL); }
 
+#ifdef READLINE
+ulong readline_state = DO_ARGS_COMPLETE;
+#endif
+
 static GEN
 sd_rl(char *v, int flag)
 {
 #ifdef READLINE
+  static const char * const msg[] = {NULL,
+	"(bits 0x2/0x4 control matched-insert/arg-complete)"};
+  ulong o_readline_state;
+  GEN res;
+
   if (!readline_init && *v && *v != '0') {
     init_readline();
     readline_init = 1;
   }
+  o_readline_state = readline_state;
+  res = sd_ulong(v,flag,"readline", &readline_state, 0, 3, (char**)msg);
+  if (o_readline_state != readline_state)
+    sd_gptoggle(readline_state ? "1" : "0", d_SILENT, "readline", USE_READLINE);
+  return res;
+#else
+    sd_gptoggle(v, flag, "readline", USE_READLINE);
 #endif
-  return sd_gptoggle(v,flag,"readline", USE_READLINE);
 }
 
 static GEN
@@ -2209,10 +2224,13 @@ brace_color(char *s, int c, int force)
 {
   if (disable_color || (gp_colors[c] == c_NONE && !force)) return;
 #ifdef RL_PROMPT_START_IGNORE
-  *s++ = RL_PROMPT_START_IGNORE;
+  if (GP_DATA->flags & USE_READLINE)
+    *s++ = RL_PROMPT_START_IGNORE;
 #endif
   strcpy(s, term_get_color(c));
 #ifdef RL_PROMPT_START_IGNORE
+  if (!(GP_DATA->flags & USE_READLINE))
+    return;
   s+=strlen(s);
   *s++ = RL_PROMPT_END_IGNORE; *s = 0;
 #endif
--- ./src/gp/gp.h-pre3	Tue Jun 11 17:24:10 2002
+++ ./src/gp/gp.h	Thu Oct 17 02:38:18 2002
@@ -30,6 +30,10 @@ extern ulong init_opts;
 extern char *current_logfile;
 extern jmp_buf environnement;
 
+extern ulong readline_state;
+#define DO_MATCHED_INSERT	2
+#define DO_ARGS_COMPLETE	4
+
 /* for do_time() */
 enum { ti_NOPRINT, ti_REGULAR, ti_LAST, ti_INTERRUPT };