;; To try out this example, copy and paste the entire contents of everything
;; in this answer to the `*scratch*' buffer and type: M-x eval-buffer RET
;; Then type: M-x db-example RET
;;
;; `db-open-file' also works out-of-the-box by typing: M-x db-open-file RET
;;
;;
;; The frame names are defined with the variable `db-frame-name'.
;; The preconfigured frame names are: SYSTEM, MAIN, ORG, MISCELLANEOUS.
;;
;; Buffers are displayed in specific frames based on the `buffer-name'.
;;
;; If the `buffer-name' matches a regexp defined `db-special-buffer',
;; then display that buffer in the current frame.
;;
;; If the `buffer-name' matches a regexp defined by `db-system-buffer',
;; then display that buffer in a frame named SYSTEM.
;;
;; If the `buffer-name' matches a regexp defined by `db-main-buffer',
;; then display that buffer in a frame named MAIN.
;;
;; If the `buffer-name' matches a regexp defined by `db-org-buffer',
;; then display that buffer in a frame named ORG.
;;
;; If the `buffer-name' does not match any of the above-mentioned regexp,
;; then display that buffer in a frame named MISCELLANEOUS.
;;
;;
;; The following are a few methods of setting the `display-buffer-alist':
;;
;; (1) Set the `display-buffer-alist' explicitly with `setq':
;;
;; (setq display-buffer-alist '((".*" . (db-pop-up-frame))))
;;
;; (2) Add to an existing `display-buffer-alist' using `add-to-list':
;;
;; (add-to-list 'display-buffer-alist '(".*" . (db-pop-up-frame)))
;;
;; (3) Call the function as part of the `display-buffer' statement:
;;
;; (display-buffer (get-buffer-create "foo") '(db-pop-up-frame))
;;
;; (4) Use the `display-buffer-alist' on a let-bound basis:
;;
;; (let ((display-buffer-alist '((".*" . (db-pop-up-frame)))))
;; [any additional code] )
(defvar db-frame-name "^\\(?:SYSTEM\\|MAIN\\|ORG\\|MISCELLANEOUS\\)$"
"Frame names that are used to help organize buffers.")
(defvar db-system-buffer '("\\*scratch\\*" "\\*bbdb\\*" "\\*bar\\*")
"Regexp of file / buffer names displayed in frame `SYSTEM`.")
(defvar db-main-buffer
'("\\.txt" "\\.tex" "\\.el" "\\.yasnippet" "\\*foo\\*")
"Regexp of file / buffer names displayed in frame `MAIN`.")
(defvar db-org-buffer
'("\\*TODO\\*" "\\*Org Agenda\\*" "\\.org_archive" "\\.org")
"Regexp of file / buffer names displayed in frame `ORG`.")
(defvar db-special-buffer
'("\\*special\\*" "\\*baz\\*")
"Regexp of file / buffer names that will display in current frame.")
(defun db-pop-up-frame (buffer alist)
(cond
;; condition # 1 -- either file-visiting or no-file buffers
((db-regexp-match-p db-org-buffer (buffer-name buffer))
(if (db-get-frame--drew-adams "ORG")
(select-frame-set-input-focus (db-get-frame--drew-adams "ORG"))
;; If unnamed frame exists, then take control of it.
(catch 'break (dolist (frame (frame-list))
(if (not (string-match db-frame-name
(frame-parameter frame 'name)))
(throw 'break (progn
(select-frame-set-input-focus
(db-get-frame--drew-adams (frame-parameter frame 'name)))
(set-frame-name "ORG"))))))
;; If dolist found no unnamed frame, then create / name it.
(when (not (db-get-frame--drew-adams "ORG"))
(make-frame (list '(name . "ORG")))) )
(unless (get-buffer-window buffer)
(set-window-buffer (get-largest-window) buffer))
(select-window (get-buffer-window buffer)) )
;; condition # 2 -- either file-visiting or no-file buffers
((db-regexp-match-p db-main-buffer (buffer-name buffer))
(if (db-get-frame--drew-adams "MAIN")
(select-frame-set-input-focus (db-get-frame--drew-adams "MAIN"))
;; If unnamed frame exists, then take control of it.
(catch 'break (dolist (frame (frame-list))
(if (not (string-match db-frame-name
(frame-parameter frame 'name)))
(throw 'break (progn
(select-frame-set-input-focus
(db-get-frame--drew-adams (frame-parameter frame 'name)))
(set-frame-name "MAIN"))))))
;; If dolist found no unnamed frame, then create / name it.
(when (not (db-get-frame--drew-adams "MAIN"))
(make-frame (list '(name . "MAIN")))) )
(unless (get-buffer-window buffer)
(set-window-buffer (get-largest-window) buffer))
(select-window (get-buffer-window buffer)) )
;; condition # 3 -- either file-visiting or no-file buffers
((db-regexp-match-p db-system-buffer (buffer-name buffer))
(if (db-get-frame--drew-adams "SYSTEM")
(select-frame-set-input-focus (db-get-frame--drew-adams "SYSTEM"))
;; If unnamed frame exists, then take control of it.
(catch 'break (dolist (frame (frame-list))
(if (not (string-match db-frame-name
(frame-parameter frame 'name)))
(throw 'break (progn
(select-frame-set-input-focus
(db-get-frame--drew-adams (frame-parameter frame 'name)))
(set-frame-name "SYSTEM"))))))
;; If dolist found no unnamed frame, then create / name it.
(when (not (db-get-frame--drew-adams "SYSTEM"))
(make-frame (list '(name . "SYSTEM")))) )
(unless (get-buffer-window buffer)
(set-window-buffer (get-largest-window) buffer))
(select-window (get-buffer-window buffer)) )
;; condition # 4
;; display buffer in the existing frame
((db-regexp-match-p db-special-buffer (buffer-name buffer))
(unless (get-buffer-window buffer)
(set-window-buffer (get-largest-window) buffer))
(select-window (get-buffer-window buffer)) )
;; condition # 5
;; file-visiting buffers that do NOT match any pre-defined regexp
((and (not (db-regexp-match-p db-org-buffer (buffer-name buffer)))
(not (db-regexp-match-p db-main-buffer (buffer-name buffer)))
(not (db-regexp-match-p db-system-buffer (buffer-name buffer)))
(not (db-regexp-match-p db-special-buffer (buffer-name buffer)))
(buffer-file-name (get-buffer (buffer-name buffer))))
(if (db-get-frame--drew-adams "MISCELLANEOUS")
(select-frame-set-input-focus
(db-get-frame--drew-adams "MISCELLANEOUS"))
;; If unnamed frame exists, then take control of it.
(catch 'break (dolist (frame (frame-list))
(if (not (string-match db-frame-name
(frame-parameter frame 'name)))
(throw 'break (progn
(select-frame-set-input-focus
(db-get-frame--drew-adams (frame-parameter frame 'name)))
(set-frame-name "MISCELLANEOUS"))))))
;; If dolist found no unnamed frame, then create / name it.
(when (not (db-get-frame--drew-adams "MISCELLANEOUS"))
(make-frame (list '(name . "MISCELLANEOUS")))) )
(unless (get-buffer-window buffer)
(set-window-buffer (get-largest-window) buffer))
(select-window (get-buffer-window buffer)) )
;; condition # 6
;; default display for no-file-visiting buffers
(t nil )))
;; https://github.com/kentaro/auto-save-buffers-enhanced
;; `db-regexp-match-p` function modified by @sds on stackoverflow
;; http://stackoverflow.com/a/20343715/2112489
(defun db-regexp-match-p (regexps string)
(and string
(catch 'matched
(let ((inhibit-changing-match-data t))
(dolist (regexp regexps)
(when (string-match regexp string)
(throw 'matched t)))))))
;; Original Author: Drew Adams -- http://www.emacswiki.org/emacs/frame-fns.el
;; @lawlist combined the functions `get-frame-name` and `get-a-frame`.
(defun db-get-frame--drew-adams (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."
(let ((get-frame-name--drew-adams
(lambda (&optional frame)
(unless frame (setq frame (selected-frame)))
(if (framep frame)
(cdr (assq 'name (frame-parameters frame)))
(error "Argument not a frame: `%s'" frame)))))
(cond ((framep frame) frame)
((stringp frame)
(catch 'get-a-frame-found
(dolist (fr (frame-list))
(when (string= frame (funcall get-frame-name--drew-adams fr))
(throw 'get-a-frame-found fr)))
nil))
(t
(error "Arg neither a string nor a frame: `%s'" frame)))))
(defun db-open-file (&optional filename)
"With assistance from the `display-buffer-alist', locate or create a
specific frame, and then open the file."
(interactive)
(let ((display-buffer-alist '((".*" . (db-pop-up-frame)))))
(display-buffer (find-file-noselect
(if filename
filename
(if (eq system-type 'darwin)
(ns-read-file-name "Select File: " "~/" t nil nil)
(read-file-name "Select File: " "~/" nil nil nil nil) ))))))
(when (eq system-type 'darwin)
(defun db-ns-find-file ()
"Do a `find-file' with the `ns-input-file' as argument."
(interactive)
(let* (
(display-buffer-alist '((".*" . (db-pop-up-frame))))
(f (file-truename (expand-file-name (pop ns-input-file)
command-line-default-directory))) )
(ns-hide-emacs 'activate)
(display-buffer (find-file-noselect f))))
(defalias 'ns-find-file 'db-ns-find-file) )
(defun db-example ()
"This is an example that uses the custom function `db-pop-up-frame' to
display buffers in different frames or windows depending upon the situation.
The `auto-mode-alist' is set to `nil` due to a bug in one of the versions
of `org-mode' where it attempts to recenter a window that is not visible."
(interactive)
;; condition # 3 | file-visiting buffer
(let* (
(auto-mode-alist nil)
(display-buffer-alist '((".*" . (db-pop-up-frame)))) )
(display-buffer (find-file-noselect "*bar*"))
(set-frame-height (selected-frame) 20)
(set-frame-width (selected-frame) 80)
(set-frame-position (selected-frame) 0 0)
(message "\*bar\* appears in frame name SYSTEM.")
(sit-for 2)
;; condition # 4(a) | no-file-visiting buffer
(display-buffer (get-buffer-create "*default*"))
(message "NO-FILE buffer existing frame.")
(sit-for 2)
;; condition # 2(a) | file-visiting buffer
(display-buffer (find-file-noselect "foo.txt"))
(set-frame-height (selected-frame) 20)
(set-frame-width (selected-frame) 80)
(set-frame-position (selected-frame) 100 100)
(message "\"foo.txt\" appears in frame name MAIN.")
(sit-for 2)
;; condition # 1 | file-visiting buffer
(display-buffer (find-file-noselect "doe.org"))
(set-frame-height (selected-frame) 20)
(set-frame-width (selected-frame) 80)
(set-frame-position (selected-frame) 200 200)
(message "\"doe.org\" appears in frame name ORG.")
(sit-for 2)
;; condition # 4(b) | file-visiting buffer
(display-buffer (find-file-noselect "*special*"))
(message "FILE buffer existing frame.")
(sit-for 2)
;; condition # 6 | no-file-visiting buffer default display
(calendar)
(message "Default for no-file-visiting-buffers.")
(sit-for 2)
;; condition # 5 | file-visiting buffer with no pre-defined regexp.
(display-buffer (find-file-noselect "*undefined*"))
(set-frame-height (selected-frame) 20)
(set-frame-width (selected-frame) 80)
(set-frame-position (selected-frame) 300 300)
(message "\*IS\* buffer-filename. \*NOT\* defined by any particular regexp.")
(sit-for 2)
;; condition # 2(b) | no-file-visiting buffer
(display-buffer (get-buffer-create "*foo*"))
(set-frame-height (selected-frame) 20)
(set-frame-width (selected-frame) 80)
(set-frame-position (selected-frame) 400 400)
(message "\*NOT\* buffer-filename. \*IS\* defined by db-main-buffer.")
(sit-for 2)
(kill-buffer "*foo*")
(kill-buffer "*bar*")
(kill-buffer "*default*")
(kill-buffer "*undefined*")
(kill-buffer "*Calendar*")
(kill-buffer "*special*")
(kill-buffer "foo.txt")
(kill-buffer "doe.org")
(make-frame)
(delete-frame (db-get-frame--drew-adams "SYSTEM"))
(delete-frame (db-get-frame--drew-adams "MAIN"))
(delete-frame (db-get-frame--drew-adams "ORG"))
(delete-frame (db-get-frame--drew-adams "MISCELLANEOUS"))
(message "THE END.")))