thomas%UTAH-GR%utah-cs@sri-unix.UUCP (11/18/83)
From: Spencer W. Thomas <thomas%UTAH-GR@utah-cs> Well, I've found fixes for 2 bugs in Gosling's Emacs. The first bug is in both versions, the second *seems* to be only in #264. Bug 1 Description: Sometimes executing a function while in the minibuffer "erases" the minibuffer display. It comes back when the next key is typed. Repeat-by: Load this function (defun (bug1 (save-excursion (error-occurred (error-message "error"))) (beginning-of-file) (set-mark) (end-of-file) (erase-region) (insert-string "abcde") (novalue) )) (in #85, change the spelling of error-occurred) Bind this to a convenient key (say ESC-'), then do ESC-xinsert-string ESC-' You should get either a blank minibuffer or a minibuffer with only "abcde" in it (no insert-string prompt). Typing any character (e.g., ^E) should fix the display. Fix: The problem is that an error erases the minibuffer prompt string. Emacs has remembered it, but doesn't know it's supposed to restore it if you catch the error (with error-occurred). My fix is to add an extra check for resetting the minibuffer string at the beginning of DoDsp. So, in window.c$DoDsp, add the following lines after GSaveMiniBuf = SaveMiniBuf: /* If the minibuffer got wiped, but should be re-displayed, * restore it */ if (MiniBuf && !GSaveMiniBuf && !*MiniBuf && ResetMiniBuf) { MiniBuf = ResetMiniBuf; if (*ResetMiniBuf == 0) ResetMiniBuf = 0; } ---------------------------------------------------------------- Bug 2 Description: This bug is apparently only in #264, but the code in #85 is identical, as far as I can tell. It seems to have been caused by a change which keeps the minibuffer visible when process output occurs. The following mlisp function illustrates the problem: (defun (foo (save-excursion (pop-to-buffer "main") (erase-buffer) (arg 1 "long prompt for input, type something: ") (save-window-excursion (insert-string "this is a test\nline 2\nline 3\n") (sit-for 0) (next-page) (sit-for 0) (message "barf") (sit-for 10) ) )) ) If you load this and execute ESC-xfoo, then type <cr> to the argument prompt, you get the following sequence in the minibuffer: long prompt for input, type something: barf prompt for input, type something: : (foo) => 10or input, type something: If you change it so it only inserts two lines, then all is well, i.e., you get long prompt for input, type something: barf : (foo) => 10 Fix: This one is somewhat complicated (as you might expect, it turned out to be in the skull-and-crossbones section, display.c). If more than 3 lines may have changed, then emacs performs the full-blown redisplay algorithm (this is why the bug doesn't appear with only two lines inserted). (Note: Take the following with a grain of salt, it is my interpretation of the code, and may be wrong, but it did lead to an apparently correct solution.) If the minibuffer hasn't changed, and the redisplay is caused by a function call (like sit-for), then emacs does not redraw the minibuffer, so the DesiredScreen lines for the minibuffer contents are null (not just empty). For normal screen lines (in a buffer, e.g.), it is not clear that this can ever happen. It will happen if a one-line optimization is being done, but then the slow update won't be performed, so there's no problem. Now, if a DesiredScreen line is null, it is set to the corresponding PhysScreen line, to indicate that there is no change. Then, down in the bowels of CalcID, the following sequence occurs: (line i from the previous screen is being mapped onto line j of the new screen) 1. Remember the old line i. 2. If the desired line i is the same, forget it. 3. Forget the PhysScreen copy of the old line i. Assuming a null DesiredScreen line, both PhysScreen[i] and DesiredScreen[i] are null now. This assumption takes us to. Also assume (valid in minibuffer) that lines i and j are really the same line. 4. If the old line is not the same line (structure) as PhysScreen[j] and DesiredScreen[j], forget it. Now, with our assumptions, we have that 1. PhysScreen[j] is null 2. Line j on the screen is NOT blank, but emacs thinks it is because of 1. Next time we put something into the minibuffer (message "barf"), emacs thinks that line is blank and just writes "barf" on top of it. The fix just sets PhysScreen[j] to its old value when i == j and the desired line is identical to the current line. Even if you didn't follow all that, here is a fix. In display.c$UpdateScreen, make the following change: diff -c1 -r3.3 display.c *** /tmp/,RCSt1006077 Fri Nov 11 23:41:53 1983 --- display.c Fri Nov 11 23:22:46 1983 *************** *** 451,453 CalcID (ni, nj, 0); ! if (InputPending && !DoneEarly) { if (PhysScreen[j] != old) --- 451,455 ----- CalcID (ni, nj, 0); ! if ( i == j && !PhysScreen[i] && !DesiredScreen[i] ) ! PhysScreen[i] = old; ! else if (InputPending && !DoneEarly) { if (PhysScreen[j] != old) ---------------------------------------------------------------- Finally, here is a fix to #85 to make the minibuffer stick around, even when process output occurs. This is something I came up with for #85, and does not need to be put into #264 which does the same thing differently: in window.c$DoDsp, near the end (shortly after the label update:), comment out the lines below. } ! /* else if (!GSaveMiniBuf) ! MiniBuf = *MiniBuf ? "" : 0;*/ } In keyboard.c$GetChar, add the lines indicated below. The context is what it looks like in the original #85 and #264 versions, as far as I can tell. c = getc(stdin); InputPending = stdin->_cnt>0; } #endif + if (MiniBuf && (!InMiniBuf || *MiniBuf) && !ResetMiniBuf) + MiniBuf = *MiniBuf ? "" : 0; /* Only reset minibuf w/ kbd input */ if(c<0) return -1; HaveCharacter: Sorry about the length of this message, seems I had a lot to say. =Spencer