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

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

bug#4041: 23.0.92; Emacs 23: buffer point is no longer frame-local


From: martin rudalics
Subject: bug#4041: 23.0.92; Emacs 23: buffer point is no longer frame-local
Date: Sat, 08 Oct 2011 15:23:29 +0200
User-agent: Thunderbird 2.0.0.21 (Windows/20090302)

> Assume you have buffer B open on frame F in windows T, U and V,
> respectively displaying B at positions P1, P2 and P3.  Now in window
> W, also on F, you C-x b to switch to B.  Today it takes you to P1,
> assuming T is next in the window-list.

Hardly.  It takes you to P1 because presumably window T is selected and
the window point of the selected window usually coincides with that
window's buffer's point.

> If no window were currently
> showing B, then W would display point-min.

Hopefully not.  W should display the buffer's `point' (which, if the
buffer was never shown before, would coincide with `point-min').

> Let's call this the "existing-window" behavior, as for a new window W it
> will choose a position from an existing window.

Not necessarily.  If another window were selected and, in B you go to
some other position, the next `switch-to-buffer' will display B around
`point' which might not coincide with any of the other windows'
positions.

> If you were to make my
> proposed multi-frame change, I think you could reasonably choose to
> retain the existing-window behavior within a frame, as it preserves the
> current intra-frame buffer-switching semantics.
>
> However, over the decades I have noticed that when I have two or
> more windows open to the same buffer on the same frame, it is almost
> always because I want to establish N > 1 persistent working locations
> within that buffer.  In fact it is rarely useful to have two windows open
> to the same buffer location, as they merely echo each other.  So
> I would posit that my "multiple persistent working locations" use case
> is likely to be the most common reason for users to have N > 1
> windows displaying the same buffer in a given frame.

Having "two or more windows open to the same buffer" sounds like a
reasonable condition.  The problem is that you might have no window
showing the buffer and still want to restore the previous window
position.  That's why `switch-to-prev-buffer' is superior to any
`switch-to-buffer' changing solution.  Notwithstanding Lars' argument
that people are used to C-x b, tell me why `switch-to-prev-buffer'
(combined with `switch-to-next-buffer') doesn't do what you want.

> The problem with today's "existing-window" behavior is that if you
> have window T displaying buffer B on frame F at buffer position P,
> then you can not sustain a *persistent* working location P' in any
> other window U on F.  By "persistent", I specifically mean that in
> window U, if I switch temporarily away to another buffer and then
> back, I want to go back to P'.  Today it takes me to P:   I have lost
> my working location in U.

Not with `switch-to-prev-buffer' ;-)

> I have long found this behavior most unfortunate.  Ironically, the
> best workaround is to visit B in window X on a second frame G.
> Then no matter what happens to the window configuration in F,
> X will retain its window point at your second working location P'.
>
> Trying to work around it within F requires that you disturb your
> window configuration, or attempt to track your working locations
> with the mark ring, or some other relatively unnatural workflow.
> At least, I find it unnatural compared to my desired workflow:
>
>   - open a window T and display buffer B at position Pt
>   - in window U switch to buffer B (it defaults to Pt, which is fine)
>   - then in U:
>     * move to a different position Pu in B
>     * switch to any other buffer C (e.g. Info, shell, ...)
>     * switch back to buffer B

This should be `switch-to-prev-buffer'.

>     * continue working at Pu
>
> This workflow, which I think of as "persistent window positions",
> would actually be closest to how Emacs works in the most
> common use case of all:  single-frame, single-window.  If you are
> visiting B at position P, and you switch away, then back, you will
> return to P.  It is easy to think of this as the window remembering
> where you last were in B.  If you think of it this way, as I do, then
> you are constantly surprised that windows suffer from amnesia
> whenever more than one of them is displaying the same buffer.
> It feels to me that they should behave as if they are independent.
>
> Thus I would be happiest if there were an option such that every
> window tracks the buffer positions of every buffer that it visits,

You can get these positions via `window-prev-buffers'.

> and when switching back to a buffer B that it has already visited,
> each window displays B at the same position it last displayed B.
>
> If you kill a window, its position list goes away.  New windows
> would start with a nil position list, and the first time they visit a
> buffer they would use the "existing-window" semantics:  use
> the position of the next window currently displaying the buffer,
> or else point-min.  (It might be confusing to have them choose
> from the position-list of a window that has previously visited
> the buffer but is not currently displaying it, so I'd not do that.)
>
> Similarly if you kill a buffer, then it is removed from the position
> lists for all existing windows.  If it is recreated, e.g. by opening
> the file again for file buffers, all windows would initially begin
> viewing it at point-min.
>
> I think "per-window visited-buffer last-position lists" would solve
> the multi-frame problem (4041).  I believe they would also
> clean up the IMO rather unfortunate existing semantics for
> same-buffer, same-frame, multiple windows, since the current
> behavior (a) doesn't parallel the current single-frame, single
> window behavior, and (b) doesn't allow for multiple temporary
> "persistent" working locations in multiple windows in a single
> buffer on a single frame.
>
> At the very least it'd be a nice global configuration option.
> I'm sure you could probably do all this with a package, but
> it's fairly fundamental -- it would be nice, for example, to be
> able to enable it by setting a single variable on someone
> else's Emacs instance while debugging something for them.
>
> I have done an exhaustive survey of everyone sitting near
> me right now, and they both agreed that buffer positions
> should be "window-local", and that they've been annoyed
> by it forever as well.  Just wanted to cover my bases! ;)

All this has been implemented - see section 28.14 Window History in the
Elisp manual.  If you still insist on having C-x b return to the
previous position, try the definition below.

martin

(defun switch-to-buffer (buffer-or-name &optional norecord force-same-window)
  "Switch to buffer BUFFER-OR-NAME in the selected window.
If called interactively, prompt for the buffer name using the
minibuffer.  The variable `confirm-nonexistent-file-or-buffer'
determines whether to request confirmation before creating a new
buffer.

BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
nil.  If BUFFER-OR-NAME is a string that does not identify an
existing buffer, create a buffer with that name.  If
BUFFER-OR-NAME is nil, switch to the buffer returned by
`other-buffer'.

Optional argument NORECORD non-nil means do not put the buffer
specified by BUFFER-OR-NAME at the front of the buffer list and
do not make the window displaying it the most recently selected
one.

If FORCE-SAME-WINDOW is non-nil, BUFFER-OR-NAME must be displayed
in the selected window; signal an error if that is
impossible (e.g. if the selected window is minibuffer-only).  If
nil, BUFFER-OR-NAME may be displayed in another window.

Return the buffer switched to."
  (interactive
   (list (read-buffer-to-switch "Switch to buffer: ") nil t))
  (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
    (if (null force-same-window)
        (pop-to-buffer buffer display-buffer--same-window-action norecord)
      (cond
       ;; Don't call set-window-buffer if it's not needed since it
       ;; might signal an error (e.g. if the window is dedicated).
       ((eq buffer (window-buffer)))
       ((window-minibuffer-p)
        (error "Cannot switch buffers in minibuffer window"))
       ((eq (window-dedicated-p) t)
        (error "Cannot switch buffers in a dedicated window"))
       (t
        (let* ((entry (and (get-buffer-window buffer 0)
                           (assq buffer (window-prev-buffers))))
               (start (and entry (nth 1 entry)))
               (pos (and entry (nth 2 entry))))
          (set-window-buffer nil buffer)
          (when entry
            ;; If BUFFER-OR-NAME (1) was shown in the selected window
            ;; before and (2) is currently displayed in some other
            ;; visible window, try to restore start and point of buffer
            ;; in the selected window.
            (set-window-start (selected-window) start t)
            (set-window-point-1 nil pos)))))

      (unless norecord
        (select-window (selected-window)))
      (set-buffer buffer))))






reply via email to

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