From: martin rudalics <rudalics@gmx.at>
To: Drew Adams <drew.adams@oracle.com>
Cc: 4748@emacsbugs.donarmstrong.com
Subject: bug#4748: 23.1; least recently used window - is it?
Date: Sun, 18 Oct 2009 19:36:35 +0200 [thread overview]
Message-ID: <4ADB5223.4070007@gmx.at> (raw)
In-Reply-To: <361C5607E07445959296A72FA999D368@us.oracle.com>
> 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
next prev parent reply other threads:[~2009-10-18 17:36 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-18 8:41 bug#4748: 23.1; least recently used window - is it? Drew Adams
2009-10-18 10:24 ` martin rudalics
2009-10-18 16:30 ` Drew Adams
2009-10-18 17:36 ` martin rudalics [this message]
2009-10-18 18:48 ` Drew Adams
2009-10-19 7:36 ` martin rudalics
2009-10-19 1:58 ` Stefan Monnier
2009-10-19 6:28 ` Drew Adams
2009-10-19 13:57 ` Stefan Monnier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4ADB5223.4070007@gmx.at \
--to=rudalics@gmx.at \
--cc=4748@emacsbugs.donarmstrong.com \
--cc=drew.adams@oracle.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).