[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