all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
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







  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

* 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 external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.