Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to intercept a file before it opens and decide which frame

Tags:

emacs

I am looking for some ideas, please, regarding how to intercept a file before it opens and make a decision which frame to open it in.

I have a modified version of frame-bufs by Alp Aker -- https://github.com/alpaker/Frame-Bufs -- that is working with a current version of Emacs Trunk. I wrote a function that associates the file being opened with the frame that has focus. I'd like to take it one step further and set up a list of file types and buffer names that will always be associated with a particular frame. I was thinking about a function that does something like this:

* If the file being opened is
     (or (eq major-mode 'text-mode) (eq major-mode 'latex-mode) )
          (switch-to-frame "TEXT")

* If the buffer being opened is
     (or (equal (buffer-name) "Folder") (equal (buffer-name) "Summary") )
          (switch-to-frame "WANDERLUST")

* After completing either of the above, open the file / buffer.

* Run the custom frame association function -- (associate-current-buffer)

I assume that it is possible to figure out what mode a file is before it is actually opened in a frame. What would be the best way to do this?

like image 944
lawlist Avatar asked Aug 20 '13 23:08

lawlist


1 Answers

;;  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.")))
like image 178
62 revs, 2 users 100% Avatar answered Oct 17 '22 17:10

62 revs, 2 users 100%