Subject: Re: bug#15189: 24.3.50; display-buffer does not work well with custom frames.

From: Keith David Bershatsky <[email-masked]>
Date: Tue, 27 Aug 2013 15:30:09 -0700

Thank you for the suggestions and examples -- greatly appreciated !!!

Here is the revised code that appears to be working correctly for both types of situations -- i.e., file-visiting buffers, and nofile-visiting buffers.

Keith

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EXAMPLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun example ()
  (interactive)
  (custom-find-file "*bar*")
  (set-frame-position (selected-frame) 0 0)
  (minibuffer-message "\*bar\* appears in frame name SYSTEM.")
  (sit-for 3)
  (custom-find-file "foo.txt")
  (set-frame-position (selected-frame) 100 100)
  (minibuffer-message "\"foo.txt\" appears in frame name MAIN.")
  (sit-for 3)
  (custom-find-file "doe.org")
  (set-frame-position (selected-frame) 200 200)
  (minibuffer-message "\"doe.org\" appears in frame name ORG.")
  (sit-for 3)
  (custom-find-file "*undefined*")
  (set-frame-position (selected-frame) 300 300)
  (minibuffer-message "\*undefined\* appears in frame name MISCELLANEOUS.")
  (sit-for 3)
  (display-buffer (get-buffer-create "*example*"))
  (other-window 1)
  (minibuffer-message "display-buffer-alist controls where \*example\* is displayed.")
  (sit-for 3)
  (kill-buffer "*bar*")
  (kill-buffer "foo.txt")
  (kill-buffer "doe.org")
  (kill-buffer "*undefined*")
  (kill-buffer "*example*")
  (make-frame)
  (delete-frame (get-frame "SYSTEM"))
  (delete-frame (get-frame "MAIN"))
  (delete-frame (get-frame "ORG"))
  (delete-frame (get-frame "MISCELLANEOUS")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;; FILE-VISITING BUFFER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defvar lawlist-regexp-frame-names "^\\(?:MAIN\\|SYSTEM\\|ORG\\|MISCELLANEOUS\\)$"
    "Regexp matching frames with specific names.")

(defvar lawlist-system-buffer-regexp nil
  "Regexps matching `buffer-filename` for frame name `SYSTEM`.")
(setq lawlist-system-buffer-regexp '("*scratch*" "*bar*"))

(defvar lawlist-main-buffer-regexp nil
  "Regexps matching `buffer-filename` for frame name `MAIN`.")
(setq lawlist-main-buffer-regexp '("\\.txt" "\\.tex" "\\.el" "\\.yasnippet"))

(defvar lawlist-org-buffer-regexp nil
  "Regexps matching `buffer-filename` for frame name `ORG`.")
(setq lawlist-org-buffer-regexp '("[*]todo-list[*]" "\\.org_archive" "\\.org"))

(defvar buffer-filename nil)

(defun custom-find-file (&optional buffer-filename)
  "Locate or create a specific frame, and then open the file."
  (interactive)
  (unless buffer-filename (setq buffer-filename (read-file-name "Select File: ")))
    (if buffer-filename
    (progn
      (setq display-buffer-function 'lawlist-display-buffer-function)
      (display-buffer (find-file-noselect buffer-filename))
      (setq display-buffer-function nil) )))

(defun lawlist-display-buffer-function (&optional buffer flag)
  (if buffer-filename (progn
    (cond
    ((lawlist-regexp-match-p lawlist-org-buffer-regexp buffer-filename)
      (if (frame-exists "ORG")
          (switch-to-frame "ORG")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "ORG"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "ORG"))
          (progn
            (make-frame)
            (set-frame-name "ORG"))) ))
    ((lawlist-regexp-match-p lawlist-main-buffer-regexp buffer-filename)
      (if (frame-exists "MAIN")
          (switch-to-frame "MAIN")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "MAIN"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "MAIN"))
          (progn
            (make-frame)
            (set-frame-name "MAIN"))) ))
    ((lawlist-regexp-match-p lawlist-system-buffer-regexp buffer-filename)
      (if (frame-exists "SYSTEM")
          (switch-to-frame "SYSTEM")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "SYSTEM"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "SYSTEM"))
          (progn
            (make-frame)
            (set-frame-name "SYSTEM"))) ))
    ((and (not (lawlist-regexp-match-p lawlist-org-buffer-regexp buffer-filename))
            (not (lawlist-regexp-match-p lawlist-main-buffer-regexp buffer-filename))
            (not (lawlist-regexp-match-p lawlist-system-buffer-regexp buffer-filename)) )
      (if (frame-exists "MISCELLANEOUS")
          (switch-to-frame "MISCELLANEOUS")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "MISCELLANEOUS"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "MISCELLANEOUS"))
          (progn
            (make-frame)
            (set-frame-name "MISCELLANEOUS")))))
    (t
      (display-buffer-same-window)))
    (switch-to-buffer (get-file-buffer buffer-filename)) )))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAY BUFFER NO FILE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defvar system-nofile-regexp nil
  "Regexps matching `buffer-name buffer` for frame name `SYSTEM`.")
(setq system-nofile-regexp '("\\(\\*Metahelp\\*\\|\\*Help\\*\\)"))

(defvar main-nofile-regexp nil
  "Regexps matching `buffer-name buffer` for frame name `MAIN`.")
(setq main-nofile-regexp '("\\*example\\*"))

(defvar org-nofile-regexp nil
  "Regexps matching `buffer-name buffer` for frame name `ORG`.")
(setq org-nofile-regexp '("\\*Org Agenda\\*"))

(setq display-buffer-alist '((lawlist-p . (nofile-display-buffer-pop-up-frame))))

(defun lawlist-p (buffer action)
  (let ((buffer (get-buffer buffer)))
  (or
    (lawlist-regexp-match-p org-nofile-regexp (buffer-name buffer))
    (lawlist-regexp-match-p main-nofile-regexp (buffer-name buffer))
    (lawlist-regexp-match-p system-nofile-regexp (buffer-name buffer)) )))

(defun nofile-display-buffer-pop-up-frame (buffer alist)
  (cond
    ((lawlist-regexp-match-p org-nofile-regexp (buffer-name buffer))
      (if (frame-exists "ORG")
          (switch-to-frame "ORG")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "ORG"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "ORG"))
          (progn
            (make-frame)
            (set-frame-name "ORG"))) ))
    ((lawlist-regexp-match-p main-nofile-regexp (buffer-name buffer))
      (if (frame-exists "MAIN")
          (switch-to-frame "MAIN")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "MAIN"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "MAIN"))
          (progn
            (make-frame)
            (set-frame-name "MAIN"))) ))
    ((lawlist-regexp-match-p system-nofile-regexp (buffer-name buffer))
      (if (frame-exists "SYSTEM")
          (switch-to-frame "SYSTEM")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "SYSTEM"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "SYSTEM"))
          (progn
            (make-frame)
            (set-frame-name "SYSTEM"))) ))
    ((and (not (lawlist-regexp-match-p org-nofile-regexp (buffer-name buffer)))
            (not (lawlist-regexp-match-p main-nofile-regexp (buffer-name buffer)))
            (not (lawlist-regexp-match-p system-nofile-regexp (buffer-name buffer))) )
      (if (frame-exists "MISCELLANEOUS")
          (switch-to-frame "MISCELLANEOUS")
        ;; If unnamed frame exists, then take control of it.
        (catch 'break (dolist (frame (frame-list))
          (if (not (string-match lawlist-regexp-frame-names (frame-parameter frame 'name)))
            (throw 'break (progn
              (switch-to-frame (frame-parameter frame 'name))
              (set-frame-name "MISCELLANEOUS"))))))
        ;; If dolist found no unnamed frame, then create / name it.
        (if (not (frame-exists "MISCELLANEOUS"))
          (progn
            (make-frame)
            (set-frame-name "MISCELLANEOUS")))))
    (t
      (display-buffer-same-window))) )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC REGEXP FUNCTION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun lawlist-regexp-match-p (regexps string)
  (catch 'matched
    (dolist (regexp regexps)
      (if (string-match regexp string)
        (throw 'matched t)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;; GENERIC BUFFER / FRAME UTILITIES ;;;;;;;;;;;;;;;;;;;;;;;;

(defun frame-exists (frame-name)
  (not (eq nil (get-frame frame-name))))

(defun get-frame-name (&optional frame)
  "Return the string that names FRAME (a frame).  Default is selected frame."
  (unless frame (setq frame (selected-frame)))
  (if (framep frame)
      (cdr (assq 'name (frame-parameters frame)))
    (error "Function `get-frame-name': Argument not a frame: `%s'" frame)))

(defun get-frame (frame)
  "Return a frame, if any, named FRAME (a frame or a string).
  If none, return nil.
  If FRAME is a frame, it is returned."
  (cond ((framep frame) frame)
        ((stringp frame)
         (catch 'get-a-frame-found
           (dolist (fr (frame-list))
             (when (string= frame (get-frame-name fr))
               (throw 'get-a-frame-found fr)))
           nil))
        (t
         (error
          "Function `get-frame-name': Arg neither a string nor a frame: `%s'"
          frame))))

(defun switch-to-frame (frame-name)
  (let ((frames (frame-list)))
    (catch 'break
      (while frames
        (let ((frame (car frames)))
          (if (equal (frame-parameter frame 'name) frame-name)
              (throw 'break (select-frame-set-input-focus frame))
            (setq frames (cdr frames))))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

At Tue, 27 Aug 2013 08:47:19 +0200,
martin rudalics wrote:
> 
>  > Using your suggestion of find-file-noselect works well with the initial example, and then just adding (switch-to-buffer (get-file-buffer buffer-filename)) to the tail end of the lawlist-display-buffer-function.
> 
> If you want to show a file-visiting buffer in the selected window, yes.
> I'd rather add a rule that calls `display-buffer-same-window' and rewrite
> the code
> 
> (when (lawlist-regexps-match-p ...)
>    ...)
> (when (lawlist-regexps-match-p ...)
>    ...)
> 
> as
> 
> (cond
>    ((lawlist-regexps-match-p ...)
>     ...)
>    ((lawlist-regexps-match-p ...)
>     ...)
>    (t
>      (display-buffer-same-window ...)))
> 
> BTW you should also make code like
> 
>            (if (and
>                (not (equal "MAIN" (frame-parameter frame 'name)))
>                (not (equal "SYSTEM" (frame-parameter frame 'name)))
>                (not (equal "ORG" (frame-parameter frame 'name)))
>                (not (equal "WANDERLUST" (frame-parameter frame 'name)))
>                (not (equal "MISCELLANEOUS" (frame-parameter frame 'name))) )
> 
> more readable by defining a variable like
> 
> (defvar my-regexp "^\\(?:MAIN\\|SYSTEM\\|ORG\\|WANDERLUST\\| MISCELLANEOUS\\)$"
>    "My doc-string.")
> 
> and using
> 	    (not (string-match my-regexp (frame-parameter frame 'name)))
> 
> instead.
> 
> martin