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