unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* BUG: which-func-mode
@ 2003-03-05  0:36 Le Wang
  2003-03-10 18:28 ` Stefan Monnier
  0 siblings, 1 reply; 17+ messages in thread
From: Le Wang @ 2003-03-05  0:36 UTC (permalink / raw)


Hi,

I just spend a few hours debugging a situation where something was modifying 
my buffer-list behind my back, whenever I had multiple windows in the same 
frame.

It turned out that `which-func-mode' was using `walk-windows' to update the 
mode-lines in all windows.  It selects each window and forces a mode-line 
update in it.  But by selecting the window, it silently disrupts the 
`buffer-list'.  This is the bug.

If I've failed to make the problem clear for everyone, please let me know and 
I'll provide a step by step test case.  But I think this one should be fairly 
obvious.

This is the patch I've come up with, again, please provide corrections where 
required:

*** /usr/local/share/emacs/21.3.50/lisp/which-func.el   Tue Feb  4 19:31:41 2003
--- /tmp/buffer-content-5706yVU Tue Mar  4 19:31:46 2003
***************
*** 158,176 ****
  
  (defun which-func-update-1 (window)
    "Update the Which-Function mode display for window WINDOW."
!   (save-selected-window
!     (select-window window)
!     ;; Update the string containing the current function.
!     (when which-func-mode
!       (condition-case info
!         (progn
!           (setq which-func-current (or (which-function) which-func-unknown))
!           (unless (string= which-func-current which-func-previous)
!             (force-mode-line-update)
!             (setq which-func-previous which-func-current)))
!       (error
!        (which-func-mode -1)
!        (error "Error in which-func-update: %s" info))))))
  
  ;;;###autoload
  (defalias 'which-func-mode 'which-function-mode)
--- 158,175 ----
  
  (defun which-func-update-1 (window)
    "Update the Which-Function mode display for window WINDOW."
!   (set-buffer (window-buffer window))
!   ;; Update the string containing the current function.
!   (when which-func-mode
!     (condition-case info
!       (progn
!         (setq which-func-current (or (which-function) which-func-unknown))
!         (unless (string= which-func-current which-func-previous)
!           (force-mode-line-update)
!           (setq which-func-previous which-func-current)))
!       (error
!        (which-func-mode -1)
!        (error "Error in which-func-update: %s" info)))))
  
  ;;;###autoload
  (defalias 'which-func-mode 'which-function-mode)

Diff finished at Tue Mar  4 19:31:46


--
Le

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-05  0:36 BUG: which-func-mode Le Wang
@ 2003-03-10 18:28 ` Stefan Monnier
  2003-03-11 18:36   ` Richard Stallman
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2003-03-10 18:28 UTC (permalink / raw)
  Cc: emacs-devel

> I just spend a few hours debugging a situation where something was modifying 
> my buffer-list behind my back, whenever I had multiple windows in the same 
> frame.
> 
> It turned out that `which-func-mode' was using `walk-windows' to update the
> mode-lines in all windows.  It selects each window and forces a mode-line
> update in it.  But by selecting the window, it silently disrupts the
> `buffer-list'.  This is the bug.

Yes.  We need a lower-level form of `select-window' for such uses.
Actually I'd recommend naming it `with-selected-window'.

> !   (save-selected-window
> !     (select-window window)
[...]

> !   (set-buffer (window-buffer window))

I think the patch is basically more-or-less right, except for the following
issues:

- I'd use with-current-buffer over set-buffer as a matter of style.
  After all, the function's name and docstring doesn't suggest that
  it might change the current buffer.

- I'm wondering whether it's good to update all the windows.
  After all, when you have a hundred windows, it's pretty silly to
  update them all all the time.

- this brings up the old issue of buffers vs windows: the code obviously
  wants to treat each window independently, so that it does TRT if you have
  two windows showing the same buffer (at two different positions), but
  it actually odesn't work because it ends up relying on a buffer-local
  variable (there are no window-local variables in Emacs).
  Your patch thus doesn't really change the behavior but makes
  the code odd since it cycles through windows but only selects the
  corresponding buffers.

The patch below fixes the buffer/window issue and removes the "update all"
behavior.  Maybe the "update all" behvaior should be restored, but it
requires the lower-level select-window function mentioned above.

Also I noticed while hacking it up that I need to set the
risky-local-variable property on both which-func-format and
which-func-current although it seems it should only be
needed on which-func-current.  What do people think ?


	Stefan


--- which-func.el.~1.29.~	Wed Feb  5 10:55:11 2003
+++ which-func.el	Mon Mar 10 13:22:41 2003
@@ -103,6 +103,7 @@
   "Format for displaying the function in the mode line."
   :group 'which-func
   :type 'sexp)
+(put 'which-func-format 'risky-local-variable t)
 
 (defvar which-func-cleanup-function nil
   "Function to transform a string before displaying it in the mode line.
@@ -120,10 +121,11 @@
 ;;;
 (require 'imenu)
 
-(defvar which-func-current  which-func-unknown)
-(defvar which-func-previous which-func-unknown)
-(make-variable-buffer-local 'which-func-current)
-(make-variable-buffer-local 'which-func-previous)
+(defvar which-func-table (make-hash-table :test 'eq :weakness 'key))
+
+(defvar which-func-current
+  '(:eval (gethash (selected-window) which-func-table which-func-unknown)))
+(put 'which-func-current 'risky-local-variable t)
 
 (defvar which-func-mode nil
   "Non-nil means display current function name in mode line.
@@ -153,24 +155,19 @@
      (setq which-func-mode nil))))
 
 (defun which-func-update ()
-  "Update the Which-Function mode display for all windows."
-  (walk-windows 'which-func-update-1 nil 'visible))
-
-(defun which-func-update-1 (window)
-  "Update the Which-Function mode display for window WINDOW."
-  (save-selected-window
-    (select-window window)
-    ;; Update the string containing the current function.
+  ;; "Update the Which-Function mode display for all windows."
+  ;; (walk-windows 'which-func-update-1 nil 'visible))
+  "Update the Which-Function mode display for the current window."
     (when which-func-mode
       (condition-case info
-	  (progn
-	    (setq which-func-current (or (which-function) which-func-unknown))
-	    (unless (string= which-func-current which-func-previous)
-	      (force-mode-line-update)
-	      (setq which-func-previous which-func-current)))
+	(let ((current (which-function)))
+	  (unless (string= current
+			   (gethash (selected-window) which-func-table))
+	    (puthash (selected-window) current which-func-table)
+	    (force-mode-line-update)))
 	(error
 	 (which-func-mode -1)
-	 (error "Error in which-func-update: %s" info))))))
+       (error "Error in which-func-update: %s" info)))))
 
 ;;;###autoload
 (defalias 'which-func-mode 'which-function-mode)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-10 18:28 ` Stefan Monnier
@ 2003-03-11 18:36   ` Richard Stallman
  2003-03-11 19:07     ` Stefan Monnier
  0 siblings, 1 reply; 17+ messages in thread
From: Richard Stallman @ 2003-03-11 18:36 UTC (permalink / raw)
  Cc: emacs-devel

    > It turned out that `which-func-mode' was using `walk-windows' to update the
    > mode-lines in all windows.  It selects each window and forces a mode-line
    > update in it.  But by selecting the window, it silently disrupts the
    > `buffer-list'.  This is the bug.

I tried to fix this in one way last fall, by changing select-window
not to alter the frame-selected-window in some cases.  That caused
other problems.  So in December I undid that change
and tried another fix:

    2002-12-23  Richard M. Stallman  <rms@gnu.org>

	* window.el (save-selected-window): Save and restore
	selected windows of all frames.

If this doesn't fix te problem, why doesn't it?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-11 18:36   ` Richard Stallman
@ 2003-03-11 19:07     ` Stefan Monnier
  2003-03-13  7:48       ` Richard Stallman
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2003-03-11 19:07 UTC (permalink / raw)
  Cc: Stefan Monnier

>     > It turned out that `which-func-mode' was using `walk-windows' to update the
>     > mode-lines in all windows.  It selects each window and forces a mode-line
>     > update in it.  But by selecting the window, it silently disrupts the
>     > `buffer-list'.  This is the bug.
> 
> I tried to fix this in one way last fall, by changing select-window
> not to alter the frame-selected-window in some cases.  That caused
> other problems.  So in December I undid that change
> and tried another fix:
> 
>     2002-12-23  Richard M. Stallman  <rms@gnu.org>
> 
> 	* window.el (save-selected-window): Save and restore
> 	selected windows of all frames.
> 
> If this doesn't fix te problem, why doesn't it?

In his case, it seems the problem is not that the frame's selected
window is changed (which was the problem you're referring to), but
that the buffer-list is changed because Fselect_window calls
`select_window_1 (window, 1)' where the second arg causes select_window_1
to call `record_buffer (w->buffer)'.


	Stefan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-11 19:07     ` Stefan Monnier
@ 2003-03-13  7:48       ` Richard Stallman
  2003-03-14 23:46         ` Stefan Monnier
  0 siblings, 1 reply; 17+ messages in thread
From: Richard Stallman @ 2003-03-13  7:48 UTC (permalink / raw)
  Cc: monnier+gnu/emacs

I see two choices: either document that select-window can change the
buffer list order and that save-selected-window does not protect
against that, or else change save-selected-window to save and restore
the buffer list order.  I think the former is better.

Any other ideas?  Does anyone want to write it?

Meanwhile, the patch to which-func-mode seems like the right approach
there.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-13  7:48       ` Richard Stallman
@ 2003-03-14 23:46         ` Stefan Monnier
  2003-03-16  7:47           ` Richard Stallman
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2003-03-14 23:46 UTC (permalink / raw)
  Cc: Stefan Monnier

> I see two choices: either document that select-window can change the
> buffer list order and that save-selected-window does not protect
> against that, or else change save-selected-window to save and restore
> the buffer list order.  I think the former is better.

I don't necessarily like the latter, but the former doesn't solve the
problem of "how do I temporarily select another window while preventing
buffer-list from being changed?".

I think that it would be better if select-window did not change
the buffer-list.  Why does it do it in the first place ?
It seems it should be the job of things like switch-to-buffer
and other-window.


	Stefan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-14 23:46         ` Stefan Monnier
@ 2003-03-16  7:47           ` Richard Stallman
  2003-03-16  8:02             ` Stefan Monnier
  0 siblings, 1 reply; 17+ messages in thread
From: Richard Stallman @ 2003-03-16  7:47 UTC (permalink / raw)
  Cc: monnier+gnu/emacs

    I think that it would be better if select-window did not change
    the buffer-list.  Why does it do it in the first place ?

Because it changes the selected buffer.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-16  7:47           ` Richard Stallman
@ 2003-03-16  8:02             ` Stefan Monnier
  2003-03-16 12:48               ` Robert J. Chassell
  2003-03-17  4:51               ` Richard Stallman
  0 siblings, 2 replies; 17+ messages in thread
From: Stefan Monnier @ 2003-03-16  8:02 UTC (permalink / raw)
  Cc: Stefan Monnier

>     I think that it would be better if select-window did not change
>     the buffer-list.  Why does it do it in the first place ?
> 
> Because it changes the selected buffer.

I don't understand why one should imply the other.
After all, `set-buffer' also changes the selected buffer but it doesn't
modify the buffer-list.


	Stefan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-16  8:02             ` Stefan Monnier
@ 2003-03-16 12:48               ` Robert J. Chassell
  2003-03-16 22:37                 ` Stefan Monnier
  2003-03-17  4:51               ` Richard Stallman
  1 sibling, 1 reply; 17+ messages in thread
From: Robert J. Chassell @ 2003-03-16 12:48 UTC (permalink / raw)


   >     I think that it would be better if select-window did not
   >     change the buffer-list.  Why does it do it in the first place?
   > 
   > Because it changes the selected buffer.

   I don't understand why one should imply the other.
   After all, `set-buffer' also changes the selected buffer but it
   doesn't modify the buffer-list.

`set-buffer' works differently than `switch-to-buffer' or
`select-window'.  As its documentation says, `set-buffer'

    ... does not display the buffer, so its effect ends
    when the current command terminates.

This is in contrast with `switch-to-buffer' or `select-window'.

Moreover, as said in

    (elisp)The Buffer List 

    The "buffer list" is a list of all live buffers.  Creating a
    buffer adds it to this list, and killing a buffer excises it.  The
    order of the buffers in the list is based primarily on how
    recently each buffer has been displayed in the selected window.
    Buffers move to the front of the list when they are selected and
    to the end when they are buried (see `bury-buffer', below).
    Several functions, notably `other-buffer', use this ordering.  A
    buffer list displayed for the user also follows this order.

I did not deal with `select-window', but in my "Introduction to
Programming in Emacs Lisp", I did explain the difference between
`switch-to-buffer' and `set-buffer' like this:

    (eintr)Switching Buffers

    `switch-to-buffer' is designed for humans and does two different
    things: it switches the buffer to which Emacs' attention is
    directed; and it switches the buffer displayed in the window to
    the new buffer.  `set-buffer', on the other hand, does only one
    thing: it switches the attention of the computer program to a
    different buffer.  The buffer on the screen remains unchanged (of
    course, normally nothing happens there until the command finishes
    running).

Thus `set-buffer' should *not* effect the buffer list, which is
intended to list buffers displayed for humans in the selected window.

Perhaps the Emacs manual or Emacs Lisp Reference Manuals are not
sufficiently explicit about the difference among different kinds of
`set', `switch-to', and `select' functions; I don't see the problem,
but maybe the documentation should be improved.

-- 
    Robert J. Chassell                         Rattlesnake Enterprises
    http://www.rattlesnake.com                  GnuPG Key ID: 004B4AC8
    http://www.teak.cc                             bob@rattlesnake.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-16 12:48               ` Robert J. Chassell
@ 2003-03-16 22:37                 ` Stefan Monnier
  2003-03-17 12:51                   ` Robert J. Chassell
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2003-03-16 22:37 UTC (permalink / raw)
  Cc: emacs-devel

>    >     I think that it would be better if select-window did not
>    >     change the buffer-list.  Why does it do it in the first place?
>    > 
>    > Because it changes the selected buffer.
> 
>    I don't understand why one should imply the other.
>    After all, `set-buffer' also changes the selected buffer but it
>    doesn't modify the buffer-list.
> 
> `set-buffer' works differently than `switch-to-buffer' or
> `select-window'.  As its documentation says, `set-buffer'
> 
>     ... does not display the buffer, so its effect ends
>     when the current command terminates.
> 
> This is in contrast with `switch-to-buffer' or `select-window'.

select-window does not "display the buffer" either.

> Moreover, as said in
> 
>     (elisp)The Buffer List 
> 
>     The "buffer list" is a list of all live buffers.  Creating a
>     buffer adds it to this list, and killing a buffer excises it.  The
>     order of the buffers in the list is based primarily on how
>     recently each buffer has been displayed in the selected window.
>     Buffers move to the front of the list when they are selected and
>     to the end when they are buried (see `bury-buffer', below).
>     Several functions, notably `other-buffer', use this ordering.  A
>     buffer list displayed for the user also follows this order.

This only talks about events where the buffer displayed in a window
is changed rather than events where the selected window is changed.

Furthermore, select-window is not a command and in the case at hand, it
is used to *temporarily* switch to some other window.

> I did not deal with `select-window', but in my "Introduction to
> Programming in Emacs Lisp", I did explain the difference between
> `switch-to-buffer' and `set-buffer' like this:

I'm not comparing switch-to-buffer to set-buffer:
I'm comparing select-window to set-buffer.
I of course agree 100% with the current behavior which does not change
the buffer-list in set-buffer but changes it in switch-to-buffer.
OTOH, I still haven't heard any good reason why select-window should
fiddle with the buffer-list.


	Stefan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-16  8:02             ` Stefan Monnier
  2003-03-16 12:48               ` Robert J. Chassell
@ 2003-03-17  4:51               ` Richard Stallman
  2003-03-17 15:30                 ` Stefan Monnier
  1 sibling, 1 reply; 17+ messages in thread
From: Richard Stallman @ 2003-03-17  4:51 UTC (permalink / raw)
  Cc: monnier+gnu/emacs

    > Because it changes the selected buffer.

    I don't understand why one should imply the other.
    After all, `set-buffer' also changes the selected buffer but it doesn't
    modify the buffer-list.

set-buffer only changes the current buffer; it doesn't change
the selected buffer, which is the buffer that is displayed
in the selected window.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-16 22:37                 ` Stefan Monnier
@ 2003-03-17 12:51                   ` Robert J. Chassell
  2003-03-18 13:22                     ` Richard Stallman
  0 siblings, 1 reply; 17+ messages in thread
From: Robert J. Chassell @ 2003-03-17 12:51 UTC (permalink / raw)
  Cc: emacs-devel

You are right, there is a confusion regarding `select-window'.

As you point out

    select-window does not "display the buffer"

and as is said in

    (elisp)The Buffer List 

    .... The order of the buffers in the list is based primarily on
    how recently each buffer has been displayed in the selected
    window.  Buffers move to the front of the list when they are
    selected....

Put another way, to be on the buffer list, a buffer must have been:

  * displayed in a window

  * that window selected

But according to its documentation, `select-window' only does the
latter.  It does not do both.

I think the confusion arises because a window always displays
something -- after all that is what a window is.  And in Emacs what a
window displays is a buffer.

Hence, `select-window' must display a buffer of some sort, although
nothing specifies which buffer is displayed.

Consequently, the two criteria for going onto the buffer list are met:
`select-window' must display some buffer in the window, and it also
selects the window.  Unfortunately, the documentation does not make
this clear.

-- 
    Robert J. Chassell                         Rattlesnake Enterprises
    http://www.rattlesnake.com                  GnuPG Key ID: 004B4AC8
    http://www.teak.cc                             bob@rattlesnake.com

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-17  4:51               ` Richard Stallman
@ 2003-03-17 15:30                 ` Stefan Monnier
  2003-03-17 23:24                   ` Richard Stallman
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2003-03-17 15:30 UTC (permalink / raw)
  Cc: Stefan Monnier

>     > Because it changes the selected buffer.
> 
>     I don't understand why one should imply the other.
>     After all, `set-buffer' also changes the selected buffer but it doesn't
>     modify the buffer-list.
> 
> set-buffer only changes the current buffer; it doesn't change
> the selected buffer, which is the buffer that is displayed
> in the selected window.

Oh, I think I now understand the subtle difference.  Thank you.
So now: how should we make it possible to temporarily select another
window without influencing the buffer-list ?


	Stefan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-17 15:30                 ` Stefan Monnier
@ 2003-03-17 23:24                   ` Richard Stallman
  2003-03-18  0:53                     ` Stefan Monnier
  0 siblings, 1 reply; 17+ messages in thread
From: Richard Stallman @ 2003-03-17 23:24 UTC (permalink / raw)
  Cc: monnier+gnu/emacs

    So now: how should we make it possible to temporarily select another
    window without influencing the buffer-list ?

You can write a macro that would save buffer-list and afterward put it
back the way it was.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-17 23:24                   ` Richard Stallman
@ 2003-03-18  0:53                     ` Stefan Monnier
  2003-03-19  8:49                       ` Richard Stallman
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2003-03-18  0:53 UTC (permalink / raw)
  Cc: Stefan Monnier

>     So now: how should we make it possible to temporarily select another
>     window without influencing the buffer-list ?
> 
> You can write a macro that would save buffer-list and afterward put it
> back the way it was.

How can I (re)set the buffer-list from elisp ?
If it requires C coding, then I might as well add a NORECORD argument
to select-window and avoid the whole save/restore.


	Stefan


PS: This is also related to the comment I added a while back
to Fpop_to_buffer:

  if (NILP (norecord))
    /* This seems bogus since Fselect_window will call record_buffer anyway. */
    record_buffer (buf);
  Fselect_window (Fdisplay_buffer (buf, other_window, Qnil));

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-17 12:51                   ` Robert J. Chassell
@ 2003-03-18 13:22                     ` Richard Stallman
  0 siblings, 0 replies; 17+ messages in thread
From: Richard Stallman @ 2003-03-18 13:22 UTC (permalink / raw)
  Cc: monnier+gnu/emacs

    You are right, there is a confusion regarding `select-window'.

I will clarify this in the Lisp manual.  Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: BUG: which-func-mode
  2003-03-18  0:53                     ` Stefan Monnier
@ 2003-03-19  8:49                       ` Richard Stallman
  0 siblings, 0 replies; 17+ messages in thread
From: Richard Stallman @ 2003-03-19  8:49 UTC (permalink / raw)
  Cc: monnier+gnu/emacs

    How can I (re)set the buffer-list from elisp ?

You could select all the buffers in the desired order.
However, that would alter the current frame's buffer list.
So maybe that new arg to select-window is the best idea.

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2003-03-19  8:49 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-03-05  0:36 BUG: which-func-mode Le Wang
2003-03-10 18:28 ` Stefan Monnier
2003-03-11 18:36   ` Richard Stallman
2003-03-11 19:07     ` Stefan Monnier
2003-03-13  7:48       ` Richard Stallman
2003-03-14 23:46         ` Stefan Monnier
2003-03-16  7:47           ` Richard Stallman
2003-03-16  8:02             ` Stefan Monnier
2003-03-16 12:48               ` Robert J. Chassell
2003-03-16 22:37                 ` Stefan Monnier
2003-03-17 12:51                   ` Robert J. Chassell
2003-03-18 13:22                     ` Richard Stallman
2003-03-17  4:51               ` Richard Stallman
2003-03-17 15:30                 ` Stefan Monnier
2003-03-17 23:24                   ` Richard Stallman
2003-03-18  0:53                     ` Stefan Monnier
2003-03-19  8:49                       ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).