Ilya Zakharevich on Sat, 25 Apr 1998 06:21:12 +0200


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

Yet another readline update


a) I'm using _rl_save/restore_prompt() when I need to change prompt;
b) Giving 0-arg to ([{ makes them non-electric from this point on;
c) Giving negative-arg to ([{ makes them electric from this point on;
d) Giving 0-arg to TAB makes it to not insert args from this point on;
e) Giving negative-arg to TAB makes it insert args from this point on;
f) Forward/backward-sexp implemented (put on Alt-Left/Right and C-M-F/B);

Difference of Forward/backward-sexp from the Emacs ones: if you are
after `(' and go sexp-back, you go one char back (and ding()), similar
with forward (Emacs just ding()).

When you change the state of electricity, you get a message what happened.

This is an incremental diff -pu with what I sent before (2.0.5).

Enjoy,
Ilya

--- ./src/gp/gp_rl.c.pre-arg	Sun Apr 19 14:57:08 1998
+++ ./src/gp/gp_rl.c	Sat Apr 25 00:01:56 1998
@@ -34,6 +34,7 @@ typedef char* (*GF)(char*,int); /* gener
 
 static int pari_rl_back;
 extern Function *rl_last_func;
+static int do_args_complete = 1;
 
 /* Wrapper around rl_complete to allow insertion of () with a point in
    between. */
@@ -43,6 +44,19 @@ pari_rl_complete(int count, int key)
     int ret;
     
     pari_rl_back = 0;
+    if (count <= 0) {			/* Change the state */
+	int c;
+	
+	do_args_complete = (count != 0);
+	_rl_save_prompt();
+	rl_message( "complete args: %s. %s" , 
+		    ( do_args_complete ? "on" : "off"), rl_prompt);
+	c = rl_read_key();
+	_rl_restore_prompt();
+	rl_clear_message();
+	rl_stuff_char (c);
+	return 1;
+    }
     rl_begin_undo_group();
     if (rl_last_func == pari_rl_complete)
 	rl_last_func = rl_complete;	/* Make repeated TABs different */
@@ -55,16 +69,30 @@ pari_rl_complete(int count, int key)
 
 static const char paropen[] = "([{";
 static const char parclose[] = ")]}";
+static int do_matched_insert = 1;
 
 /* To allow insertion of () with a point in between. */
 static int
 pari_rl_matched_insert(int count, int key)
 {
     int i = 0, ret;
-    
+
+    if (count <= 0) {			/* Change the state */
+	int c;
+	
+	do_matched_insert = (count != 0);
+	_rl_save_prompt();
+	rl_message( "electric parens: %s. %s" , 
+		    ( do_matched_insert ? "on" : "off"), rl_prompt);
+	c = rl_read_key();
+	_rl_restore_prompt();
+	rl_clear_message();
+	rl_stuff_char (c);
+	return 1;
+    }
     while (paropen[i] && paropen[i] != key)
 	i++;
-    if (!paropen[i])
+    if (!paropen[i] || !do_matched_insert)
 	return rl_insert(count,key);
     rl_begin_undo_group();
     rl_insert(count,key);
@@ -74,6 +102,85 @@ pari_rl_matched_insert(int count, int ke
     return ret;
 }
 
+static int
+pari_rl_forward_sexp(int count, int key)
+{
+    int i = 0, deep = 0, dir = (count >= 0 ? 1 : -1), move_point, lfail;
+
+    if (count < 0)
+	count = -count;
+    if (dir < 0) {
+	if (rl_point) 
+	    rl_point--;
+	else
+	    goto fail;
+    }
+    while (count || deep) {
+	move_point = 1;		/* Need to move point if moving left. */
+	lfail = 0;		/* Do not need to fail left movement yet. */
+	while ( !is_keyword_char(rl_line_buffer[rl_point])
+		&& !strchr("\"([{}])",rl_line_buffer[rl_point])
+		&& !( (dir == 1) 
+		      ? (rl_point >= rl_end) 
+		      : (rl_point <= 0 && (lfail = 1))))
+	    rl_point += dir;
+	if (lfail) 
+	    goto fail;
+	if (!rl_line_buffer[rl_point]) {
+	    goto fail;
+	} else if (is_keyword_char(rl_line_buffer[rl_point])) {
+	    while ( is_keyword_char(rl_line_buffer[rl_point])
+		    && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
+			|| (move_point = 0)))
+		rl_point += dir;
+	    if (!deep)
+		count--;
+	} else if (strchr(paropen,rl_line_buffer[rl_point])) {
+	    if (deep == 0 && dir == -1)	/* We are already out of pars. */
+		goto fail;
+	    rl_point += dir;
+	    deep += 1;
+	    if (!deep)
+		count--;
+	} else if (strchr(parclose,rl_line_buffer[rl_point])) {
+	    if (deep == 0 && dir == 1) {
+		rl_point++;		/* Get out of pars. */
+		goto fail;
+	    }
+	    rl_point += dir;
+	    deep -= 1;
+	    if (!deep)
+		count--;
+	} else if (rl_line_buffer[rl_point] == '\"') {
+	    int bad = 1;
+	    
+	    rl_point += dir;
+	    while ( ((rl_line_buffer[rl_point] != '\"') || (bad = 0))
+		    && (!((dir == 1) ? (rl_point >= rl_end) : (rl_point <= 0))
+			|| (move_point = 0)) )
+		rl_point += dir;
+	    if (bad)
+		goto fail;
+	    rl_point += dir;	/* Skip the other delimiter */
+	    if (!deep)
+		count--;
+	} else {			/* Hit boundary. */
+	  fail:
+	    ding();
+	    return 1;
+	}
+    }
+    if (dir != 1 && move_point)
+	rl_point++;
+    return 1;
+}
+
+static int
+pari_rl_backward_sexp(int count, int key)
+{
+    return pari_rl_forward_sexp(-count, key);
+}
+
 /* 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
@@ -341,6 +448,7 @@ pari_completion (char *text, int start, 
     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] )
+	 && do_args_complete
 	 && (iend - i < MAX_KEYWORD)
 	 && ( strncpy(buf, rl_line_buffer + i, iend - i),
 	      buf[iend - i] = 0, 1)
@@ -386,14 +494,19 @@ rl_short_help(int count, int key)
   while (off && is_keyword_char(rl_line_buffer[off-1])) off--;
   rl_point = 0; rl_end = 0; outfile = rl_outstream; 
   if (count < 0) flag |= h_LONG; /* long help */
+  _rl_save_prompt();
   ((void(*)(const char*))rl_message)("");
+
+#if 0					/* _rl_save/restore_prompt does it. */
   /* Erase prompt. */
   pariputs("\r");
   while (l--)
       pariputs(" ");
   pariputs("\r");
+#endif 
 
   aide(rl_line_buffer + off, flag);
+  _rl_restore_prompt();
   rl_point = p; rl_end = e; outfile = save; 
   rl_clear_message(); 
   rl_refresh_line(); return 0;
@@ -433,9 +546,13 @@ init_readline(int i)
   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);
+  Defun("pari-forward-sexp", (Function*) pari_rl_forward_sexp, -1);
+  Defun("pari-backward-sexp", (Function*) pari_rl_backward_sexp, -1);
 
   Bind('h', (Function*) rl_short_help, emacs_meta_keymap);
   Bind('H', (Function*) rl_long_help,  emacs_meta_keymap);
+  Bind(6, (Function*) pari_rl_forward_sexp,  emacs_meta_keymap); /* M-C-f */
+  Bind(2, (Function*) pari_rl_backward_sexp,  emacs_meta_keymap); /* M-C-b */
   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);
@@ -445,6 +562,8 @@ init_readline(int i)
 #  ifdef EMACS_DOS_KEYMAP
      Bind(';', (Function*) rl_short_help, emacs_dos_keymap); /* F1 */
      Bind('T', (Function*) rl_long_help,  emacs_dos_keymap); /* Shift-F1 */
+     Bind(155, (Function*) pari_rl_backward_sexp,  emacs_dos_keymap); /* Alt-Left */
+     Bind(157, (Function*) pari_rl_forward_sexp,  emacs_dos_keymap); /* Alt-Right */
 #  endif
 }
 #endif