[gnu.bash.bug] bash 1.03 - Bad cursor optimization

cudcv@warwick.ac.uk (Rob McMahon) (09/02/89)

Bash 1.03 still exhibits the same bad cursor optimisation:

Having noticed the cursor `bouncing' on the first character of a line, I
decided to investigate:

Here's the TERMCAP, I've chopped it into short lines for news:

Mu|sun:am:bs:km:mi:ms:pt:li#34:co#80:cl=^L:cm=\E[%i%d;%dH:ce=\E[K:cd=\E[J:\
	:so=\E[7m:se=\E[m:rs=\E[s:al=\E[L:dl=\E[M:im=:ei=:ic=\E[@:dc=\E[P:\
	:up=\E[A:nd=\E[C:ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:k1=\E[224z:\
	:k2=\E[225z:k3=\E[226z:k4=\E[227z:k5=\E[228z:k6=\E[229z:k7=\E[230z:\
	:k8=\E[231z:k9=\E[232z:AL=\E[%dL:DL=\E[%dM:IC=\E[%d@:DC=\E[%dP:

I typed `echo^M^P^Aecho ^M^D' to bash, and this is an `od -c' of the
typescript:
 
Script started on Sat Sep  2 15:23:38 1989
cudcv (35) >> od -c script2
(... this bit's boring ...)
0000240                                    b   a   s   h   $       e  \b
first character bounces						   ^^^^^
0000260    e   c   h   o  \r  \r  \n  \r  \n   b   a   s   h   $       e
0000300    c   h   o  \b  \b  \b  \b  \b  \b  \b  \b  \b  \b 033   [   2
very slow way to get to left margin   ^^^^^^^^^^^^^^^^^^^^^^
0000320    @   *   b   a   s   h   $       e 033   [   1   @   c   e  \b
(unnecessary `1' here, not very important)	       ^
every time a character is inserted, the one after is redrawn   ^^^^^^^^^
0000340  033   [   1   @   h   e  \b 033   [   1   @   o   e  \b 033   [
0000360    1   @       e  \b  \r  \r  \n   e   c   h   o  \r  \n   b   a
			      ^^^^^^
(always get 2 carriage returns, not very important)
(... etc)
cudcv (36) >> x
exit

script done on Sat Sep  2 15:24:27 1989

The two carriage returns I take to be because the shell doesn't turn off
output translations, nor check to see whether they are enabled or not.  The
first is probably a feature, the second doesn't seem worth fixing.

I believe the problems in readline.c are
1) in rl_redisplay the first characters of the visible and invisible buffers
   are compared before the invisible one is filled in when dealing with the
   first redisplay on the line.
2) in update_line, if the loop finding the last same character ends because of
   meeting the first difference, rather than because of finding two characters
   that don't match, the pointers already point at the last same, and don't
   need incrementing.
3) I've made an optimization to move_cursor_relative to move backwards by
   doing a carriage return and then moving forwards if that is faster.
   Although it is called move_cursor_relative, the argument is in fact
   absolute.
4) In passing I noticed that term_im is not output when using the multiple
   insert, as I believe it should be.
5) I changed start_insert to use term_ic rather than term_IC if only one
   character is to be inserted.

The patches at the end seem to fix all but the double cr problem, make of them
what you will, I don't seem to have broken anything as far as I can tell.  The
resulting `od -c' is:

Script started on Sat Sep  2 15:34:29 1989
cudcv (39) >> od -c script2
...
0002460                                    b   a   s   h   $       e   c
no bounce							   ^
0002500    h   o  \r  \r  \n  \r  \n   b   a   s   h   $       e   c   h
still doubled cr  ^^^^^^
0002520    o  \b  \b  \b  \b  \r 033   [   2   @   *   b   a   s   h   $
cr to return to left	      ^^
0002540        e 033   [   @   c 033   [   @   h 033   [   @   o 033   [
only draw single character inserted	       ^
ic rather than IC for single inserts		 ^^^^^^^^^^^
0002560    @      \r  \r  \n   e   c   h   o  \r  \n   b   a   s   h   $
...
cudcv (40) >> x
exit

script done on Sat Sep  2 15:35:34 1989

===================================================================
RCS file: readline.c,v
retrieving revision 1.1
diff -c -r1.1 readline.c
*** /tmp/,RCSt1a06819	Sat Sep  2 15:36:56 1989
--- readline.c	Sat Sep  2 15:36:40 1989
***************
*** 907,918 ****
        line[out] = '\0';
      }
  
-   /* If someone thought that the redisplay was handled, but the currently
-      visible line has a different modification state than the one about
-      to become visible, then correct the callers misconception. */
-   if (visible_line[0] != invisible_line[0])
-     rl_display_fixed = 0;
- 
    strncpy (line + out,  rl_display_prompt, strlen (rl_display_prompt));
    out += strlen (rl_display_prompt);
    line[out] = '\0';
--- 907,912 ----
***************
*** 960,965 ****
--- 954,965 ----
    if (c_pos < 0)
      c_pos = out;
  
+   /* If someone thought that the redisplay was handled, but the currently
+      visible line has a different modification state than the one about
+      to become visible, then correct the callers misconception. */
+   if (visible_line[0] != invisible_line[0])
+     rl_display_fixed = 0;
+ 
    /* PWP: now is when things get a bit hairy.  The visible and invisible
       line buffers are really multiple lines, which would wrap every
       (screenwidth - 1) characters.  Go through each in turn, finding
***************
*** 1115,1121 ****
        ols = oe;
        nls = ne;
      }
!   else
      {
        if (*ols)			/* don't step past the NUL */
  	ols++;
--- 1115,1121 ----
        ols = oe;
        nls = ne;
      }
!   else if (*ols != *nls)
      {
        if (*ols)			/* don't step past the NUL */
  	ols++;
***************
*** 1232,1238 ****
--- 1232,1246 ----
       char *data;
  {
    register int i;
+   static void output_character_function ();
  
+   /* may be faster to do cr then move forwards than to move backwards. */
+   if (new + 1 < last_c_pos - new)
+     {
+       tputs (term_cr, 1, output_character_function);
+       last_c_pos = 0;
+     }
+ 
    if (last_c_pos == new) return;
  
    if (last_c_pos < new)
***************
*** 1248,1254 ****
  	 data is underneath the cursor. */
  #ifdef HACK_TERMCAP_MOTION
        extern char *term_forward_char;
-       static void output_character_function ();
  
        if (term_forward_char)
  	for (i = last_c_pos; i < new; i++)
--- 1256,1261 ----
***************
*** 1520,1526 ****
  start_insert (count)
       int count;
  {
!   if (term_IC && *term_IC)
      {
        char *tgoto (), *buffer;
        buffer = tgoto (term_IC, 0, count);
--- 1527,1537 ----
  start_insert (count)
       int count;
  {
!   if (term_im && *term_im)
!     tputs (term_im, 1, output_character_function);
! 
!   if (term_IC && *term_IC
!       && (count > 1 || !term_ic || !*term_ic))
      {
        char *tgoto (), *buffer;
        buffer = tgoto (term_IC, 0, count);
***************
*** 1528,1536 ****
      }
    else
      {
-       if (term_im && *term_im)
- 	tputs (term_im, 1, output_character_function);
- 
        if (term_ic && *term_ic)
  	while (count--)
  	  tputs (term_ic, 1, output_character_function);
--- 1539,1544 ----

Rob
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             ARPA:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England