bug-gnu-emacs
[Top][All Lists]
Advanced

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

bug#4748: 23.1; least recently used window - is it?


From: martin rudalics
Subject: bug#4748: 23.1; least recently used window - is it?
Date: Sun, 18 Oct 2009 19:36:35 +0200
User-agent: Thunderbird 2.0.0.21 (Windows/20090302)

> The name, and the description overall (especially up to that point), seem to
> suggest that the function speaks for the notion: it returns the window that is
> actually least recently used. The reader is thus misled (at least up to that
> point).

Maybe.  I'll leave this to people more literate.

>> I suppose it's for historical reasons.  `get-lru-window'
>> should provide a window useful for displaying a buffer.
>> On older displays full-width windows were probably more useful.
>
> So rename it
> `get-the-window-Emacs-cleverly-thinks-is-the-most-useful-to-display' or
> something, and deprecate the name that is misleading.

The behavior was introduced nearly 25 years ago by this change

1985-09-07  Richard M. Stallman  (rms@mit-prep)

        ...
        * window.c (Fget_lru_window):
        Give preference to full-width windows.

so I think we should leave that alone.

> Same problem for function `get-largest-window'. The behavior is such that you 
do
> not necessarily get the largest window. (Yes, I know, that's documented.)

Where do you see a difference in the documentation of `get-lru-window'?

>>  > What I would really like to be able to is to _set_ the
>>  > least recently used window - however Emacs wants to define that.
>>
>> You can do that by temporarily selecting all other windows ...
>
> Tell me how, please.
>
> Consider this, for instance. You might think that it would cause the selected
> window (`owin') to become the lru window, and then to be used by 
`pop-to-buffer'
> for its display.
>
> (let ((owin  (selected-window)))
>   (while (not (eq (get-lru-window) owin))
>    (other-window 1)))
>
> And that works . . . except for some windows, in which case it loops forever.
> IOW, there are apparently some windows that are never lru (in the sense of
> `get-lru-window').

Well, we know that there are such windows.

> So please tell me how to do it (e.g. "by temporarily selecting all other
> windows").

Something like

(let ((owin (selected-window)))
  (dolist (window (window-list))
    (unless (eq window owin)
      (select-window window)))
  (get-lru-window))

> Which means you cannot use `pop-up-buffer' in any reasonable way to get the
> window-selection behavior of `switch-to-buffer'. Or else please show me how.

Maybe.  My `switch-to-buffer' is in Elisp for quite some time.  It goes
like

(defun switch-to-buffer (buffer-or-name &optional norecord)
  "Switch to buffer BUFFER-OR-NAME in the selected window.
If BUFFER-OR-NAME does not identify an existing buffer, then this
function creates a buffer with that name.

When called from Lisp, BUFFER-OR-NAME may be a buffer, a string
\(a buffer name), or nil.  If BUFFER-OR-NAME is nil, then this
function chooses a buffer using `other-buffer'.  Optional second
arg NORECORD non-nil means do not put this buffer at the front of
the list of recently selected ones.  This function returns the
buffer it switched to.

WARNING: This is NOT the way to work on another buffer
temporarily within a Lisp program!  Use `set-buffer' instead.
That avoids messing with the window-buffer correspondences."
  (interactive "BSwitch to buffer:\nP")
  (cond
   ((eq buffer-or-name (window-buffer))
    ;; Basically a NOP.  Avoid signalling an error in the case where
    ;; the selected window is dedicated, or a minibuffer.

    ;; But do put this buffer at the front of the buffer list, unless
    ;; that has been inhibited.  Note that even if BUFFER is at the
    ;; front of the main buffer-list already, we still want to move it
    ;; to the front of the frame's buffer list.
    (unless norecord
      (record-buffer buffer-or-name)
      (set-buffer buffer-or-name)))
   ((or (window-minibuffer-p) (eq (window-dedicated-p) t))
    (pop-to-buffer buffer-or-name nil norecord))
   (t
    (let (buffer)
      (if buffer-or-name
          (progn
            (setq buffer (get-buffer buffer-or-name))
            (unless buffer
              (setq buffer (get-buffer-create buffer-or-name))
              (set-buffer-major-mode buffer)))
        (setq buffer (other-buffer (current-buffer))))
      (set-buffer buffer)
      (unless norecord
        (record-buffer buffer))
      (set-window-buffer nil buffer)
      buffer))))

but you can't try that on your system because you don't have
`record-buffer' (you could comment out the call though).

> `switch-to-buffer', which Stefan says repeatedly (and it sounds right to me)
> should not be used in Lisp code (i.e. should be used pretty much only
> interactively), does not respect `special-display-regexps',
> `special-display-buffer-names', or `pop-up-frames'.

Because it wouldn't make much sense to respect these ;-)

> And yet `switch-to-buffer' _is_ used in Lisp code, including in the Emacs
> sources. It is called from commonly used commands, such as 
`bookmark-bmenu-list'
> and `view-buffer'/`view-file' (which means, e.g., `view-emacs-news').

We'd have to look at each of these cases to tell whether they can use
`pop-to-buffer' directly.

> Presumably, there is a common use case there that should be respected: someone
> wants to substitute for the current buffer preferably in the same window,
> instead of opening a new window and moving focus there. Dunno if that's a
> reasonable use case - I never need that behavior myself, but it seems to be
> fairly common.

I can't tell.  Obviously `same-window-buffer-names' and friends
implicitly provide the same service.

> Assuming we should be able to meet that use case, what's the right replacement
> for `switch-to-buffer' for that case?

If and when we enhance `display-buffer' with a same-window argument
`switch-to-buffer' could become obsolete (for Elisp calls).  OTOH this
might lead programmers to call `display-buffer' with the same-window
argument in these and other cases.

> What code will do the same thing wrt which
> window gets used and which buffer will be put in place after using, say,
> `quit-window' in the newly displayed buffer?

Does `quit-window' behave differently wrt whether `switch-to-buffer' was
called or `pop-to-buffer'?

> The above code loops forever in some cases (e.g. C-x 2 C-x 3; put 3 diff 
buffers
> in the windows; then the small, right-hand window will never be used by
> `pop-to-buffer'. That is, this will not work:
>
> (cond ((one-window-p) ; This part works.
>        (pop-to-buffer (get-buffer-create "*foo*"))
>        (delete-other-windows))
>       (t ; This part works except for some windows.
>        (let ((owin  (selected-window)))
>          (while (not (eq (get-lru-window) owin))
>            (other-window 1)))
>        (pop-to-buffer (get-buffer-create "*foo*"))))
>
> (You'll recommend comparing with the root window, instead of calling
> `one-window-p', but that doesn't change the point in question.)

You shouldn't use `other-window' because it doesn't bury the window as
you expect.  Loop over `window-list' instead.

> Here's another attempt, which at least doesn't loop forever: Replace the `let'
> sexp above by this:
>
> (dotimes (i (1- (count-windows))) (other-window 1))
>
> That suffers from more or less the same problem: the newly displayed buffer is
> never shown in the right-hand window - the full-width window is always used
> whenever the right-hand window is selected. (But of course this preference for
> full-width is inconsistent - the just-as-small left-hand window _is_ used to
> display the buffer. IOW, this dwim does not dwim.)
>
> [You cannot just use (other-window (1- (count-window)) instead of a loop,
> because that doesn't cycle the window-selection (lru) order.]

I still don't understand why and how you want to control the setting of
the LRU window in practice.

> And if you have the same buffer in more than one window, then such "solutions"
> also behave differently from `switch-to-buffer' when you use `quit-window'. 
E.g.
> C-x 2 C-x 3, without using 3 different buffers, etc.

In what sense do they behave differently?

> 1. The reason for avoiding `switch-to-buffer' here, and using `pop-to-buffer'
> instead, is so that variables such as `special-display-*' and `pop-up-frames'
> will be respected. E.g., if `special-display-regexps' is ("[ ]?[*][^*]+[*]"),
> then *foo* will be opened in its own, special frame.

Good.

> 2. The reason for trying to simulate `switch-to-buffer's 
which-window-gets-used
> behavior and its `quit-window' behavior

I still don't understand - what is `switch-to-buffer's `quit-window'
behavior?

> is that such behavior is apparently a
> common use case. If replacing `switch-to-buffer' in, say, `view-buffer', we
> would presumably want to keep the same behavior as now for users who do not 
use
> `special-display-*' and `pop-up-frames'.

So try to experiment with the following: Have `display-buffer' interpret
a 'same-window value for the NOT-THIS-WINDOW argument and replace calls
like (switch-to-buffer buffer) with (pop-to-buffer buffer 'same-window).

> Again, dunno about #2. Maybe we should just forget about that use case and
> replace `switch-to-buffer' willy nilly by `pop-to-buffer'/`display-buffer'?
>
> Or maybe we should redefine `switch-to-buffer' so that it respects the 
variables
> in question (and possibly other relevant variables, if any). IOW, make it use
> `display-buffer'. (Why doesn't it?)

It does (if the selected window is dedicated).

> And perhaps add a parameter to `display-buffer' to let you use the same window
> or specify the window to use?

See above.

> Or perhaps allow you to more easily set the least
> recently used window and specify that the full-width stuff be ignored?

I wouldn't object that.

> Or (more likely) maybe I'm missing something, and there is already a 
reasonable
> way to get both (a) the `switch-to-buffer' behavior wrt window selection and
> `quit-window' and (b) the `display-buffer' behavior wrt the use-another-frame
> variables?
>
> In which case, please enlighten me. How should we replace `switch-to-buffer' 
in,
> say, `view-buffer' or `bookmark-bmenu-list' (or...)?

First you have to enlighten me wrt the quit-window behavior.

>>  > Currently, it doesn't seem easy to predict or control
>>  > which window is used by things such as `pop-to-buffer'
>>  > that try to use another window. Being able to set the
>>  > so-called lruw that such functions use would
>>  > make things a lot more straightforward.
>>
>> We can easily remove the FULL-WIDTH feature.  But _who_ would be
>> responsible for "touching" windows in order to make them LRU?
>
> I would do it in my code - if it worked.

But it's the _user_ who should touch the windows, not the application
programmer.

> But the main question is posed above. Given the aim of, in effect, making
> `pop-to-buffer' use a particular window, I tried to somehow set a window to be
> the lru. But that doesn't work because of the full-width criterion.
>
> When there is no substitute for a clever, behind-the-scenes dwim behavior, 
users
> (including Elisp users) lose control. Even if the under-cover magic DTRT 99% 
of
> the time (which is not certain), there should be some reasonable way for
> programmers to control the behavior (get beyond the dwim).
>
> I was hoping that simply making a window be the least recently used one would
> cause `pop-to-buffer' to use that window. But things are apparently far from 
so
> simple. I'm hoping you or someone else (e.g. Stefan) has a simple solution 
that
> I've been blind to.

Stefan has proposed to enhance the NOT-THIS-WINDOW argument of
`display-buffer' for this purpose and I'm all for it.

martin







reply via email to

[Prev in Thread] Current Thread [Next in Thread]