Subject: Re: bug#9761: proposed list-buffers change -- revert buffer if point is in *Buffer List* buffer

From: Zachary Kanfer <[email-masked]>
Date: Sat, 10 Dec 2011 01:48:39 -0500

I have included two diffs in this email. The first is the diff without
whitespace, generated by bzr diff lisp/buff-menu.el --no-aliases
--diff-options="-cp -w" . The second is the full diff, as generated by bzr
diff lisp/buff-menu.el --no-aliases --diff-options=-cp . I introduced a
`let` statement which wraps a large majority of the function, so a large
part of the full diff is merely whitespace changes. The no-whitespace diff
shows more clearly the code changes I've made. I could have used setq to
avoid introducing a new level of nesting, but didn't want to leak new
variables outside the function. I will change it, if advised that it's
better practice.

The majority of my changes happen near the end of the method. I get the
*Buffer List* window, and the current window. If the *Buffer List* window
exists, I select it. I then move point to the correct position, and restore
the selected window if necessary.

Diff #1 (diff ignoring whitespace):

=== modified file 'lisp/buff-menu.el'
*** lisp/buff-menu.el    2011-09-18 20:43:20 +0000
--- lisp/buff-menu.el    2011-12-09 06:18:25 +0000
*************** For more information, see the function `
*** 807,812 ****
--- 807,815 ----
        (setq header (concat (propertize " " 'display '(space :align-to 0))
                 header)))
      (with-current-buffer (get-buffer-create "*Buffer List*")
+       (let ((line-number (line-number-at-pos))
+             (column-number (current-column)))
+         (message (concat "line: " (number-to-string line-number) "\tcol:
" (number-to-string column-number)))
          (setq buffer-read-only nil)
          (erase-buffer)
          (setq standard-output (current-buffer))
*************** For more information, see the function `
*** 857,863 ****
                 ?\s)))
          (unless file
            ;; No visited file.  Check local value of
!           ;; list-buffers-directory and, for Info buffers,
            ;; Info-current-file.
            (cond ((and (boundp 'list-buffers-directory)
                    list-buffers-directory)
--- 860,866 ----
                               ?\s)))
                    (unless file
                      ;; No visited file.  Check local value of
!                     ;; list-buffers-diectory and, for Info buffers,
                      ;; Info-current-file.
                      (cond ((and (boundp 'list-buffers-directory)
                                  list-buffers-directory)
*************** For more information, see the function `
*** 896,903 ****
                   (string< (nth Buffer-menu-sort-column a)
                        (nth Buffer-menu-sort-column b)))))
           list))
-     (if (eq (car buffer) old-buffer)
-         (setq desired-point (point)))
      (insert (cadr buffer)
          ;; Put the buffer name into a text property
          ;; so we don't have to extract it from the text.
--- 899,904 ----
*************** For more information, see the function `
*** 929,941 ****
        (Buffer-menu-mode)
        (when Buffer-menu-use-header-line
      (setq header-line-format header))
!       ;; DESIRED-POINT doesn't have to be set; it is not when the
!       ;; current buffer is not displayed for some reason.
!       (and desired-point
!        (goto-char desired-point))
        (setq Buffer-menu-files-only files-only)
        (setq Buffer-menu--buffers buffer-list)
        (set-buffer-modified-p nil)
!       (current-buffer))))

  ;;; buff-menu.el ends here
--- 930,950 ----
          (Buffer-menu-mode)
          (when Buffer-menu-use-header-line
            (setq header-line-format header))
!         (let ((buffer-list-window (get-window-with-predicate
!                                    (lambda (window)
!                                          (string= "*Buffer List*"
!                                                   (buffer-name
(window-buffer window))))))
!               (current-window (selected-window)))
!           (when buffer-list-window
!             (select-window buffer-list-window))
!           (goto-char (point-min))
!           (forward-line (1- line-number))
!           (forward-char column-number)
!           (when buffer-list-window
!             (select-window current-window)))
          (setq Buffer-menu-files-only files-only)
          (setq Buffer-menu--buffers buffer-list)
          (set-buffer-modified-p nil)
!         (current-buffer)))))

  ;;; buff-menu.el ends here

Diff #2 (full diff):

=== modified file 'lisp/buff-menu.el'
*** lisp/buff-menu.el    2011-09-18 20:43:20 +0000
--- lisp/buff-menu.el    2011-12-09 06:18:25 +0000
*************** For more information, see the function `
*** 807,941 ****
        (setq header (concat (propertize " " 'display '(space :align-to 0))
                 header)))
      (with-current-buffer (get-buffer-create "*Buffer List*")
!       (setq buffer-read-only nil)
!       (erase-buffer)
!       (setq standard-output (current-buffer))
!       ;; Force L2R direction, to avoid messing the display if the
!       ;; first buffer in the list happens to begin with a strong R2L
!       ;; character.
!       (setq bidi-paragraph-direction 'left-to-right)
!       (unless Buffer-menu-use-header-line
!         ;; Use U+2014 (EM DASH) to underline if possible, else use ASCII
!         ;; (i.e. U+002D, HYPHEN-MINUS).
!     (let ((underline (if (char-displayable-p ?\u2014) ?\u2014 ?-)))
!       (insert header
!           (apply 'string
!              (mapcar (lambda (c)
!                    (if (memq c '(?\n ?\s)) c underline))
!                  header)))))
!       ;; Collect info for every buffer we're interested in.
!       (dolist (buffer (or buffer-list
!               (buffer-list
!                (when Buffer-menu-use-frame-buffer-list
!                  (selected-frame)))))
!     (with-current-buffer buffer
!       (let ((name (buffer-name))
!         (file buffer-file-name))
!         (unless (and (not buffer-list)
!              (or
!               ;; Don't mention internal buffers.
!               (and (string= (substring name 0 1) " ") (null file))
!               ;; Maybe don't mention buffers without files.
!               (and files-only (not file))
!               (string= name "*Buffer List*")))
!           ;; Otherwise output info.
!           (let ((mode (concat (format-mode-line mode-name nil nil buffer)
!                   (if mode-line-process
!                       (format-mode-line mode-line-process
!                             nil nil buffer))))
!             (bits (string
!                (if (eq buffer old-buffer) ?. ?\s)
!                ;; Handle readonly status.  The output buffer
!                ;; is special cased to appear readonly; it is
!                ;; actually made so at a later date.
!                (if (or (eq buffer standard-output)
!                    buffer-read-only)
!                    ?% ?\s)
!                ;; Identify modified buffers.
!                (if (buffer-modified-p) ?* ?\s)
!                ;; Space separator.
!                ?\s)))
!         (unless file
!           ;; No visited file.  Check local value of
!           ;; list-buffers-directory and, for Info buffers,
!           ;; Info-current-file.
!           (cond ((and (boundp 'list-buffers-directory)
!                   list-buffers-directory)
!              (setq file list-buffers-directory))
!             ((eq major-mode 'Info-mode)
!              (setq file Info-current-file)
!              (cond
!               ((equal file "dir")
!                (setq file "*Info Directory*"))
!               ((eq file 'apropos)
!                (setq file "*Info Apropos*"))
!               ((eq file 'history)
!                (setq file "*Info History*"))
!               ((eq file 'toc)
!                (setq file "*Info TOC*"))
!               ((not (stringp file))  ;; avoid errors
!                (setq file nil))
!               (t
!                (setq file (concat "("
!                           (file-name-nondirectory file)
!                           ") "
!                           Info-current-node)))))))
!         (push (list buffer bits name (buffer-size) mode file)
!               list))))))
!       ;; Preserve the original buffer-list ordering, just in case.
!       (setq list (nreverse list))
!       ;; Place the buffers's info in the output buffer, sorted if
necessary.
!       (dolist (buffer
!            (if Buffer-menu-sort-column
!            (sort list
!              (if (eq Buffer-menu-sort-column 3)
!                  (lambda (a b)
!                    (< (nth Buffer-menu-sort-column a)
!                   (nth Buffer-menu-sort-column b)))
!                (lambda (a b)
!                  (string< (nth Buffer-menu-sort-column a)
!                       (nth Buffer-menu-sort-column b)))))
!          list))
!     (if (eq (car buffer) old-buffer)
!         (setq desired-point (point)))
!     (insert (cadr buffer)
!         ;; Put the buffer name into a text property
!         ;; so we don't have to extract it from the text.
!         ;; This way we avoid problems with unusual buffer names.
!         (let ((name (nth 2 buffer))
!               (size (int-to-string (nth 3 buffer))))
!           (Buffer-menu-buffer+size name size
!                  `(buffer-name ,name
!                        buffer ,(car buffer)
!                        font-lock-face buffer-menu-buffer
!                        mouse-face highlight
!                        help-echo
!                        ,(if (>= (length name)
!                         (- Buffer-menu-buffer+size-width
!                            (max (length size) 3)
!                            2))
!                         name
!                       "mouse-2: select this buffer"))))
!         "  "
!         (if (> (string-width (nth 4 buffer)) Buffer-menu-mode-width)
!             (truncate-string-to-width (nth 4 buffer)
!                           Buffer-menu-mode-width)
!           (nth 4 buffer)))
!     (when (nth 5 buffer)
!       (indent-to (+ Buffer-menu-buffer-column
Buffer-menu-buffer+size-width
!             Buffer-menu-mode-width 4) 1)
!       (princ (abbreviate-file-name (nth 5 buffer))))
!     (princ "\n"))
!       (Buffer-menu-mode)
!       (when Buffer-menu-use-header-line
!     (setq header-line-format header))
!       ;; DESIRED-POINT doesn't have to be set; it is not when the
!       ;; current buffer is not displayed for some reason.
!       (and desired-point
!        (goto-char desired-point))
!       (setq Buffer-menu-files-only files-only)
!       (setq Buffer-menu--buffers buffer-list)
!       (set-buffer-modified-p nil)
!       (current-buffer))))

  ;;; buff-menu.el ends here
--- 807,950 ----
        (setq header (concat (propertize " " 'display '(space :align-to 0))
                 header)))
      (with-current-buffer (get-buffer-create "*Buffer List*")
!       (let ((line-number (line-number-at-pos))
!             (column-number (current-column)))
!         (message (concat "line: " (number-to-string line-number) "\tcol:
" (number-to-string column-number)))
!         (setq buffer-read-only nil)
!         (erase-buffer)
!         (setq standard-output (current-buffer))
!         ;; Force L2R direction, to avoid messing the display if the
!         ;; first buffer in the list happens to begin with a strong R2L
!         ;; character.
!         (setq bidi-paragraph-direction 'left-to-right)
!         (unless Buffer-menu-use-header-line
!           ;; Use U+2014 (EM DASH) to underline if possible, else use ASCII
!           ;; (i.e. U+002D, HYPHEN-MINUS).
!           (let ((underline (if (char-displayable-p ?\u2014) ?\u2014 ?-)))
!             (insert header
!                     (apply 'string
!                            (mapcar (lambda (c)
!                                      (if (memq c '(?\n ?\s)) c underline))
!                                    header)))))
!         ;; Collect info for every buffer we're interested in.
!         (dolist (buffer (or buffer-list
!                             (buffer-list
!                              (when Buffer-menu-use-frame-buffer-list
!                                (selected-frame)))))
!           (with-current-buffer buffer
!             (let ((name (buffer-name))
!                   (file buffer-file-name))
!               (unless (and (not buffer-list)
!                            (or
!                             ;; Don't mention internal buffers.
!                             (and (string= (substring name 0 1) " ") (null
file))
!                             ;; Maybe don't mention buffers without files.
!                             (and files-only (not file))
!                             (string= name "*Buffer List*")))
!                 ;; Otherwise output info.
!                 (let ((mode (concat (format-mode-line mode-name nil nil
buffer)
!                                     (if mode-line-process
!                                         (format-mode-line
mode-line-process
!                                                           nil nil
buffer))))
!                       (bits (string
!                              (if (eq buffer old-buffer) ?. ?\s)
!                              ;; Handle readonly status.  The output buffer
!                              ;; is special cased to appear readonly; it is
!                              ;; actually made so at a later date.
!                              (if (or (eq buffer standard-output)
!                                      buffer-read-only)
!                                  ?% ?\s)
!                              ;; Identify modified buffers.
!                              (if (buffer-modified-p) ?* ?\s)
!                              ;; Space separator.
!                              ?\s)))
!                   (unless file
!                     ;; No visited file.  Check local value of
!                     ;; list-buffers-diectory and, for Info buffers,
!                     ;; Info-current-file.
!                     (cond ((and (boundp 'list-buffers-directory)
!                                 list-buffers-directory)
!                            (setq file list-buffers-directory))
!                           ((eq major-mode 'Info-mode)
!                            (setq file Info-current-file)
!                            (cond
!                             ((equal file "dir")
!                              (setq file "*Info Directory*"))
!                             ((eq file 'apropos)
!                              (setq file "*Info Apropos*"))
!                             ((eq file 'history)
!                              (setq file "*Info History*"))
!                             ((eq file 'toc)
!                              (setq file "*Info TOC*"))
!                             ((not (stringp file))  ;; avoid errors
!                              (setq file nil))
!                             (t
!                              (setq file (concat "("
!                                                 (file-name-nondirectory
file)
!                                                 ") "
!                                                 Info-current-node)))))))
!                   (push (list buffer bits name (buffer-size) mode file)
!                         list))))))
!         ;; Preserve the original buffer-list ordering, just in case.
!         (setq list (nreverse list))
!         ;; Place the buffers's info in the output buffer, sorted if
necessary.
!         (dolist (buffer
!                  (if Buffer-menu-sort-column
!                      (sort list
!                            (if (eq Buffer-menu-sort-column 3)
!                                (lambda (a b)
!                                  (< (nth Buffer-menu-sort-column a)
!                                     (nth Buffer-menu-sort-column b)))
!                              (lambda (a b)
!                                (string< (nth Buffer-menu-sort-column a)
!                                         (nth Buffer-menu-sort-column
b)))))
!                    list))
!           (insert (cadr buffer)
!                   ;; Put the buffer name into a text property
!                   ;; so we don't have to extract it from the text.
!                   ;; This way we avoid problems with unusual buffer names.
!                   (let ((name (nth 2 buffer))
!                         (size (int-to-string (nth 3 buffer))))
!                     (Buffer-menu-buffer+size name size
!                                              `(buffer-name ,name
!                                                            buffer ,(car
buffer)
!                                                            font-lock-face
buffer-menu-buffer
!                                                            mouse-face
highlight
!                                                            help-echo
!                                                            ,(if (>=
(length name)
!                                                                     (-
Buffer-menu-buffer+size-width
!
(max (length size) 3)
!                                                                        2))
!                                                                 name
!                                                               "mouse-2:
select this buffer"))))
!                   "  "
!                   (if (> (string-width (nth 4 buffer))
Buffer-menu-mode-width)
!                       (truncate-string-to-width (nth 4 buffer)
!                                                 Buffer-menu-mode-width)
!                     (nth 4 buffer)))
!           (when (nth 5 buffer)
!             (indent-to (+ Buffer-menu-buffer-column
Buffer-menu-buffer+size-width
!                           Buffer-menu-mode-width 4) 1)
!             (princ (abbreviate-file-name (nth 5 buffer))))
!           (princ "\n"))
!         (Buffer-menu-mode)
!         (when Buffer-menu-use-header-line
!           (setq header-line-format header))
!         (let ((buffer-list-window (get-window-with-predicate
!                                    (lambda (window)
!                                          (string= "*Buffer List*"
!                                                   (buffer-name
(window-buffer window))))))
!               (current-window (selected-window)))
!           (when buffer-list-window
!             (select-window buffer-list-window))
!           (goto-char (point-min))
!           (forward-line (1- line-number))
!           (forward-char column-number)
!           (when buffer-list-window
!             (select-window current-window)))
!         (setq Buffer-menu-files-only files-only)
!         (setq Buffer-menu--buffers buffer-list)
!         (set-buffer-modified-p nil)
!         (current-buffer)))))

  ;;; buff-menu.el ends here

-Zachary Kanfer

On Sun, Oct 16, 2011 at 11:50 AM, Stefan Monnier
<[email-masked]>wrote:

> > !   (display-buffer (list-buffers-noselect files-only)))
> [...]
> > !   (if (string= (buffer-name)
> > !                "*Buffer List*")
> > !       (revert-buffer)
> > !     (display-buffer (list-buffers-noselect files-only))))
>
> I don't think calling revert-buffer is right.  Much better would be for
> list-buffer-noselect to try to preserve point when reusing a buffer
> rather than creating a new one.
>
>
>        Stefan
>